Skip to main content

razor_fol/
transform.rs

1/*! Implements a number of common transformations on first-order terms and formulae. */
2use super::syntax::{*, Term::*, Formula::*};
3use std::collections::HashMap;
4use std::cmp::Ordering::Equal;
5use itertools::Itertools;
6
7/// Is the trait of types that map variables to terms.
8pub trait Substitution {
9    /// Maps `v` to a [`Term`].
10    ///
11    /// [`Term`]: ../syntax/enum.Term.html
12    fn apply(&self, v: &V) -> Term;
13}
14
15/// Any function from [`V`] to [`Term`] is a substitution.
16///
17/// [`V`]: ../syntax/struct.V.html
18/// [`Term`]: ../syntax/enum.Term.html
19impl<F> Substitution for F
20    where F: Fn(&V) -> Term {
21    fn apply(&self, v: &V) -> Term {
22        self(v)
23    }
24}
25
26/// Any map from [`V`] to [`Term`] is a substitution.
27///
28/// [`V`]: ../syntax/struct.V.html
29/// [`Term`]: ../syntax/enum.Term.html
30impl Substitution for HashMap<&V, Term> {
31    fn apply(&self, v: &V) -> Term {
32        self.get(v)
33            .map(|t| t.clone())
34            .unwrap_or(v.clone().into())
35    }
36}
37
38/// Is the trait of types that map variables to variables.
39///
40/// **Note**: A variable renaming may be regarded as a special case of [`Substitution`].
41///
42/// [`Substitution`]: ../transform/trait.Substitution.html
43pub trait VariableRenaming {
44    /// Maps `v` to another [`V`].
45    ///
46    /// [`V`]: ../syntax/struct.V.html
47    fn apply(&self, v: &V) -> V;
48}
49
50/// Any function from [`V`] to [`Term`] is a variable renaming.
51///
52/// [`V`]: ../syntax/struct.V.html
53/// [`Term`]: ../syntax/enum.Term.html
54impl<F> VariableRenaming for F
55    where F: Fn(&V) -> V {
56    fn apply(&self, v: &V) -> V {
57        self(v)
58    }
59}
60
61/// Any map from [`V`] to [`Term`] is a variable renaming.
62///
63/// [`V`]: ../syntax/struct.V.html
64/// [`Term`]: ../syntax/enum.Term.html
65impl VariableRenaming for HashMap<&V, V> {
66    fn apply(&self, v: &V) -> V {
67        self.get(v)
68            .map(|var| var.clone())
69            .unwrap_or(v.clone().into())
70    }
71}
72
73/// Is the trait of objects constructed atop [`Term`]s.
74///
75/// [`Term`]: ../syntax/enum.Term.html
76pub trait TermBased {
77    /// Applies a transformation function `f` on the [`Term`]s of the receiver.
78    ///
79    /// [`Term`]: ../syntax/enum.Term.html
80    fn transform(&self, f: &impl Fn(&Term) -> Term) -> Self;
81
82    /// Applies a [`VariableRenaming`] on the variable sub-terms of the receiver.
83    ///
84    /// [`VariableRenaming`]: ../transform/trait.VariableRenaming.html
85    /// **Example**:
86    /// ```rust
87    /// # use razor_fol::syntax::{V, C, F, Term};
88    /// use razor_fol::transform::TermBased;
89    /// use std::collections::HashMap;
90    ///
91    /// // variable symbols:
92    /// let x_sym = V::from("x");
93    /// let y_sym = V::from("y");
94    /// let z_sym = V::from("z");
95    /// let a_sym = V::from("a");
96    /// let b_sym = V::from("b");
97    ///
98    /// // A variable renaming map that renames variable `x` to `a` and variable `y` to `b`
99    /// let mut renaming = HashMap::new();
100    /// renaming.insert(&x_sym, a_sym);
101    /// renaming.insert(&y_sym, b_sym);
102    ///
103    /// let x = Term::from(x_sym.clone());
104    /// let y = Term::from(y_sym.clone());
105    /// let z = Term::from(z_sym.clone());
106    /// let f = F::from("f");
107    /// let g = F::from("g");
108    ///
109    /// // t = f(x, z, g(x, y, x))
110    /// let t = f.app3(x.clone(), z.clone(), g.app3(x.clone(), y.clone(), x.clone()));
111    ///
112    /// let s = t.rename_vars(&renaming); // s = f(a, z, g(a, b, a))
113    /// assert_eq!("f(a, z, g(a, b, a))", s.to_string())
114    /// ```
115    fn rename_vars(&self, renaming: &impl VariableRenaming) -> Self;
116
117    /// Applies a [`Substitution`] on the variable sub-terms of the receiver.
118    ///
119    /// [`Substitution`]: ../transform/trait.Substitution.html
120    /// **Example**:
121    /// ```rust
122    /// # use razor_fol::syntax::{V, C, F, Term};
123    /// use razor_fol::transform::TermBased;
124    ///
125    /// // A substitution function that maps all variable symbols `x` to a constant term `c`.
126    /// // Otherwise, wraps the variable symbol in a variable term.
127    /// fn x_to_c(v: &V) -> Term {
128    ///     let x = V::from("x");
129    ///     let c = C::from("c");
130    ///
131    ///     if v == &x {
132    ///         Term::from(c)
133    ///     } else {
134    ///         Term::from(v.clone())
135    ///     }
136    /// }
137    ///
138    /// let x = Term::from(V::from("x"));
139    /// let y = Term::from(V::from("y"));
140    /// let f = F::from("f");
141    /// let g = F::from("g");
142    ///
143    /// let t = f.app2(x.clone(), g.app3(x.clone(), y.clone(), x.clone())); // t = f(x, g(x, y, x))
144    ///
145    /// let s = t.substitute(&x_to_c); // s = f('c, g('c, y, 'c))
146    /// assert_eq!("f('c, g('c, y, 'c))", s.to_string())
147    /// ```
148    fn substitute(&self, sub: &impl Substitution) -> Self;
149}
150
151impl TermBased for Term {
152    fn transform(&self, f: &impl Fn(&Term) -> Term) -> Self {
153        f(self)
154    }
155
156    fn rename_vars(&self, renaming: &impl VariableRenaming) -> Self {
157        match self {
158            Const { .. } => self.clone(),
159            Var { variable: v } => Term::from(renaming.apply(v)),
160            App { function, terms } => {
161                let terms = terms.iter()
162                    .map(|t| t.rename_vars(renaming))
163                    .collect();
164                function.clone().app(terms)
165            }
166        }
167    }
168
169    fn substitute(&self, sub: &impl Substitution) -> Self {
170        match self {
171            Const { .. } => self.clone(),
172            Var { variable: v } => sub.apply(v),
173            App { function, terms } => {
174                let terms = terms.iter()
175                    .map(|t| t.substitute(sub))
176                    .collect();
177                function.clone().app(terms)
178            }
179        }
180    }
181}
182
183impl TermBased for Formula {
184    #[inline]
185    fn transform(&self, f: &impl Fn(&Term) -> Term) -> Self {
186        match self {
187            Top | Bottom => self.clone(),
188            Atom { predicate, terms } => predicate.clone()
189                .app(terms.iter()
190                    .map(f)
191                    .collect()
192                ),
193            Equals { left, right } => f(left).equals(f(right)),
194            Not { formula } => not(formula.transform(f)),
195            And { left, right } => left
196                .transform(f)
197                .and(right.transform(f)),
198            Or { left, right } => left
199                .transform(f)
200                .or(right.transform(f)),
201            Implies { left, right } => left
202                .transform(f)
203                .implies(right.transform(f)),
204            Iff { left, right } => left
205                .transform(f)
206                .iff(right.transform(f)),
207            Exists { variables, formula } => exists(
208                variables.clone(),
209                formula.transform(f),
210            ),
211            Forall { variables, formula } => forall(
212                variables.clone(),
213                formula.transform(f),
214            ),
215        }
216    }
217
218    /// **Note**: Applies a [`VariableRenaming`] on the **free** variables of the formula, keeping
219    /// the bound variables unchanged.
220    ///
221    /// [`VariableRenaming`]: ../transform/trait.VariableRenaming.html
222    fn rename_vars(&self, renaming: &impl VariableRenaming) -> Self {
223        // this does not rename bound variables of the formula
224        self.transform(&|t: &Term| t.rename_vars(renaming))
225    }
226
227    /// **Note**: Applies a [`Substitution`] on the **free** variables of the formula, keeping the
228    /// bound variables unchanged.
229    ///
230    /// [`Substitution`]: ../transform/trait.Substitution.html
231    fn substitute(&self, substitution: &impl Substitution) -> Self {
232        self.transform(&|t: &Term| t.substitute(substitution))
233    }
234}
235
236/// Generates Skolem names in an incremental fashion in the context of any transformation that
237/// involves Skolemization.
238///
239/// **Note**: To ensure all Skolem functions in a theory are unique, the same instance of
240/// `SkolemGenerator` must be used when transforming all formulae of the theory.
241#[derive(PartialEq, Debug)]
242pub struct SkolemGenerator {
243    /// Is a prefix for the names generated by the generator.
244    prefix: String,
245    /// Is the next index to be appended to `prefix`.
246    index: i32,
247}
248
249impl SkolemGenerator {
250    /// Creates a new `SkolemGenerator` with the default prefix `"sk#"`.
251    pub fn new() -> Self {
252        Self {
253            prefix: "sk#".to_owned(),
254            index: 0,
255        }
256    }
257
258    /// Returns the next Skolem name.
259    pub fn next(&mut self) -> String {
260        let result = format!("{}{}", self.prefix, self.index);
261        self.index += 1;
262        result
263    }
264}
265
266impl From<&str> for SkolemGenerator {
267    /// Creates a `SkolemGenerator` instance with the given prefix.
268    fn from(prefix: &str) -> Self {
269        Self {
270            prefix: prefix.to_owned(),
271            index: 0,
272        }
273    }
274}
275
276impl Formula {
277    /// Returns a Prenex Normal Form (PNF) equivalent to the receiver.
278    ///
279    /// **Hint**: A PNF is a formula with all quantifiers (existential and universal) and bound
280    /// variables at the front, followed by a quantifier-free part.
281    ///
282    /// **Example**:
283    /// ```rust
284    /// # use razor_fol::syntax::Formula;
285    ///
286    /// let formula: Formula = "Q(x, y) → ∃ x, y. P(x, y)".parse().unwrap();
287    /// assert_eq!("∃ x`, y`. (Q(x, y) → P(x`, y`))", formula.pnf().to_string());
288    /// ```
289    pub fn pnf(&self) -> Formula {
290        // Appends a postfix to the input variable until the result is not no longer in the list of
291        // no collision variables.
292        fn rename(variable: &V, no_collision_variables: &Vec<&V>) -> V {
293            let mut name = variable.0.clone();
294            let names: Vec<&String> = no_collision_variables
295                .into_iter()
296                .map(|v| &v.0)
297                .collect();
298            while names.contains(&&name) {
299                name.push_str("`")
300            }
301            return V::from(&name);
302        }
303
304        // Returns a list of variables that appear in both input lists.
305        fn shared_variables<'a>(quantifier_vars: &'a Vec<V>, other_vars: &Vec<&V>) -> Vec<&'a V> {
306            quantifier_vars.iter()
307                .filter(|v| other_vars.contains(v))
308                .collect()
309        }
310
311        match self {
312            Top | Bottom | Atom { .. } | Equals { .. } => self.clone(),
313            // e.g. ~(Qx. P(x)) -> Q' x. ~P(x)
314            Not { formula } => {
315                let formula = formula.pnf();
316                match formula {
317                    Forall { variables, formula } => exists(
318                        variables,
319                        not(*formula).pnf(),
320                    ),
321                    Exists { variables, formula } => forall(
322                        variables,
323                        not(*formula).pnf(),
324                    ),
325                    _ => not(formula)
326                }
327            }
328            // e.g. (Q x. F(x)) & G(y) => Q x'. F(x') & G(y) or F(x) & (Q y. G(y)) => Q y'. F(x) & G(y')
329            And { left, right } => {
330                let left = left.pnf();
331                let right = right.pnf();
332                let left_free_variables = left.free_vars();
333                let right_free_variables = right.free_vars();
334                let mut all_free_variables = right_free_variables.clone();
335                all_free_variables.append(&mut left_free_variables.clone());
336
337                if let Forall { ref variables, ref formula } = left {
338                    let shared_vars = shared_variables(variables, &right_free_variables);
339                    let mut all_vars: Vec<&V> = variables.iter().collect();
340                    all_vars.append(&mut all_free_variables);
341
342                    let renaming = |v: &V| if shared_vars.contains(&v) {
343                        rename(v, &all_vars)
344                    } else {
345                        v.clone()
346                    };
347                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
348                    let formula = formula.rename_vars(&renaming);
349                    forall(variables, formula.and(right)).pnf()
350                } else if let Exists { ref variables, ref formula } = left {
351                    let shared_vars = shared_variables(variables, &right_free_variables);
352                    let mut all_vars: Vec<&V> = variables.iter().collect();
353                    all_vars.append(&mut all_free_variables);
354
355                    let renaming = |v: &V| if shared_vars.contains(&v) {
356                        rename(v, &all_vars)
357                    } else {
358                        v.clone()
359                    };
360                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
361                    let formula = formula.rename_vars(&renaming);
362                    exists(variables, formula.and(right)).pnf()
363                } else if let Forall { ref variables, ref formula } = right {
364                    let shared_vars = shared_variables(variables, &left_free_variables);
365                    let mut all_vars: Vec<&V> = variables.iter().collect();
366                    all_vars.append(&mut all_free_variables);
367
368                    let renaming = |v: &V| if shared_vars.contains(&v) {
369                        rename(v, &all_vars)
370                    } else {
371                        v.clone()
372                    };
373                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
374                    let formula = formula.rename_vars(&renaming);
375                    forall(variables, left.and(formula)).pnf()
376                } else if let Exists { ref variables, ref formula } = right {
377                    let shared_vars = shared_variables(variables, &left_free_variables);
378                    let mut all_vars: Vec<&V> = variables.iter().collect();
379                    all_vars.append(&mut all_free_variables);
380
381                    let renaming = |v: &V| if shared_vars.contains(&v) {
382                        rename(v, &all_vars)
383                    } else {
384                        v.clone()
385                    };
386                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
387                    let formula = formula.rename_vars(&renaming);
388                    exists(variables, left.and(formula)).pnf()
389                } else {
390                    And { left: Box::new(left), right: Box::new(right) }
391                }
392            }
393            // e.g. (Q x. F(x)) | G(y) => Q x'. F(x') | G(y) or F(x) | (Q y. G(y)) => Q y'. F(x) | G(y')
394            Or { left, right } => {
395                let left = left.pnf();
396                let right = right.pnf();
397                let left_free_variables = left.free_vars();
398                let right_free_variables = right.free_vars();
399                let mut all_free_variables = right_free_variables.clone();
400                all_free_variables.append(&mut left_free_variables.clone());
401
402                if let Forall { ref variables, ref formula } = left {
403                    let shared_vars = shared_variables(variables, &right_free_variables);
404                    let mut all_vars: Vec<&V> = variables.iter().collect();
405                    all_vars.append(&mut all_free_variables);
406
407                    let renaming = |v: &V| if shared_vars.contains(&v) {
408                        rename(v, &all_vars)
409                    } else {
410                        v.clone()
411                    };
412                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
413                    let formula = formula.rename_vars(&renaming);
414                    forall(variables, formula.or(right)).pnf()
415                } else if let Exists { ref variables, ref formula } = left {
416                    let shared_vars = shared_variables(variables, &right_free_variables);
417                    let mut all_vars: Vec<&V> = variables.iter().collect();
418                    all_vars.append(&mut all_free_variables);
419
420                    let renaming = |v: &V| if shared_vars.contains(&v) {
421                        rename(v, &all_vars)
422                    } else {
423                        v.clone()
424                    };
425                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
426                    let formula = formula.rename_vars(&renaming);
427                    exists(variables, formula.or(right)).pnf()
428                } else if let Forall { ref variables, ref formula } = right {
429                    let shared_vars = shared_variables(variables, &left_free_variables);
430                    let mut all_vars: Vec<&V> = variables.iter().collect();
431                    all_vars.append(&mut all_free_variables);
432
433                    let renaming = |v: &V| if shared_vars.contains(&v) {
434                        rename(v, &all_vars)
435                    } else {
436                        v.clone()
437                    };
438                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
439                    let formula = formula.rename_vars(&renaming);
440                    forall(variables, left.or(formula)).pnf()
441                } else if let Exists { ref variables, ref formula } = right {
442                    let shared_vars = shared_variables(variables, &left_free_variables);
443                    let mut all_vars: Vec<&V> = variables.iter().collect();
444                    all_vars.append(&mut all_free_variables);
445
446                    let renaming = |v: &V| if shared_vars.contains(&v) {
447                        rename(v, &all_vars)
448                    } else {
449                        v.clone()
450                    };
451                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
452                    let formula = formula.rename_vars(&renaming);
453                    exists(variables, left.or(formula)).pnf()
454                } else {
455                    Or { left: Box::new(left), right: Box::new(right) }
456                }
457            }
458            // e.g. (Q x. F(x)) -> G(y) => Q' x'. F(x') -> G(y) or F(x) -> (Q y. G(y)) => Q' y'. F(x) -> G(y')
459            Implies { left, right } => {
460                let left = left.pnf();
461                let right = right.pnf();
462                let left_free_variables = left.free_vars();
463                let right_free_variables = right.free_vars();
464                let mut all_free_variables = right_free_variables.clone();
465                all_free_variables.append(&mut left_free_variables.clone());
466
467                if let Forall { ref variables, ref formula } = left {
468                    let shared_vars = shared_variables(variables, &right_free_variables);
469                    let mut all_vars: Vec<&V> = variables.iter().collect();
470                    all_vars.append(&mut all_free_variables);
471
472                    let renaming = |v: &V| if shared_vars.contains(&v) {
473                        rename(v, &all_vars)
474                    } else {
475                        v.clone()
476                    };
477                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
478                    let formula = formula.rename_vars(&renaming);
479                    exists(variables, formula.implies(right)).pnf()
480                } else if let Exists { ref variables, ref formula } = left {
481                    let shared_vars = shared_variables(variables, &right_free_variables);
482                    let mut all_vars: Vec<&V> = variables.iter().collect();
483                    all_vars.append(&mut all_free_variables);
484
485                    let renaming = |v: &V| if shared_vars.contains(&v) {
486                        rename(v, &all_vars)
487                    } else {
488                        v.clone()
489                    };
490                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
491                    let formula = formula.rename_vars(&renaming);
492                    forall(variables, formula.implies(right)).pnf()
493                } else if let Forall { ref variables, ref formula } = right {
494                    let shared_vars = shared_variables(variables, &left_free_variables);
495                    let mut all_vars: Vec<&V> = variables.iter().collect();
496                    all_vars.append(&mut all_free_variables);
497
498                    let renaming = |v: &V| if shared_vars.contains(&v) {
499                        rename(v, &all_vars)
500                    } else {
501                        v.clone()
502                    };
503                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
504                    let formula = formula.rename_vars(&renaming);
505                    forall(variables, left.implies(formula)).pnf()
506                } else if let Exists { ref variables, ref formula } = right {
507                    let shared_vars = shared_variables(variables, &left_free_variables);
508                    let mut all_vars: Vec<&V> = variables.iter().collect();
509                    all_vars.append(&mut all_free_variables);
510
511                    let renaming = |v: &V| if shared_vars.contains(&v) {
512                        rename(v, &all_vars)
513                    } else {
514                        v.clone()
515                    };
516                    let variables: Vec<V> = variables.iter().map(&renaming).collect();
517                    let formula = formula.rename_vars(&renaming);
518                    exists(variables, left.implies(formula)).pnf()
519                } else {
520                    Implies { left: Box::new(left), right: Box::new(right) }
521                }
522            }
523            Iff { left, right } => left.clone()
524                .implies(*right.clone())
525                .and(right.clone().implies(*left.clone())
526                ).pnf(),
527            Exists { variables, formula } => exists(
528                variables.clone(),
529                formula.pnf(),
530            ),
531            Forall { variables, formula } => forall(
532                variables.clone(),
533                formula.pnf(),
534            ),
535        }
536    }
537
538    /// Returns a Skolem Normal Form (SNF) equivalent to the receiver.
539    ///
540    /// **Hint**: An SNF is a [PNF] with only universal quantifiers
541    /// (see: <https://en.wikipedia.org/wiki/Skolem_normal_form>).
542    ///
543    /// [PNF]: ./enum.Formula.html#method.pnf
544    ///
545    /// **Example**:
546    /// ```rust
547    /// # use razor_fol::syntax::Formula;
548    ///
549    /// let formula: Formula = "∃ y. P(x, y)".parse().unwrap();
550    /// assert_eq!("P(x, sk#0(x))", formula.snf().to_string());
551    /// ```
552    pub fn snf(&self) -> Formula {
553        self.snf_with(&mut SkolemGenerator::new())
554    }
555
556    /// Is similar to [`Formula::snf`] but uses an existing [`SkolemGenerator`] to avoid collision
557    /// when generating Skolem function names (including Skolem constants).
558    ///
559    ///
560    /// [`Formula::snf`]: ./enum.Formula.html#method.snf
561    /// [`SkolemGenerator`]: ../transform/struct.SkolemGenerator.html
562    ///
563    /// **Example**:
564    /// ```rust
565    /// # use razor_fol::syntax::Formula;
566    /// use razor_fol::transform::SkolemGenerator;
567    ///
568    /// let mut generator = SkolemGenerator::from("skolem");
569    /// let formula: Formula = "∃ y. P(x, y)".parse().unwrap();
570    /// assert_eq!("P(x, skolem0(x))", formula.snf_with(&mut generator).to_string());
571    /// ```
572    pub fn snf_with(&self, generator: &mut SkolemGenerator) -> Formula {
573        fn helper(formula: Formula, mut skolem_vars: Vec<V>, generator: &mut SkolemGenerator) -> Formula {
574            match formula {
575                Forall { variables, formula } => {
576                    skolem_vars.append(&mut variables.clone());
577                    forall(variables, helper(*formula, skolem_vars, generator))
578                }
579                Exists { variables, formula } => {
580                    let mut map: HashMap<&V, Term> = HashMap::new();
581
582                    variables.iter().for_each(|v| if skolem_vars.is_empty() {
583                        map.insert(&v, C::from(&generator.next()).into());
584                    } else {
585                        let vars: Vec<Term> = skolem_vars
586                            .iter()
587                            .map(|v| v.clone().into())
588                            .collect();
589                        map.insert(&v, F::from(&generator.next()).app(vars));
590                    });
591
592                    let substituted = formula.substitute(&map);
593                    helper(substituted, skolem_vars, generator)
594                }
595                _ => formula
596            }
597        }
598
599        // Skolemization only makes sense for PNF formulae.
600        let free_vars: Vec<V> = self.free_vars()
601            .into_iter()
602            .map(|v| v.clone())
603            .collect();
604        helper(self.pnf(), free_vars, generator)
605    }
606
607    /// Returns an Negation Normal Form (NNF) equivalent to the receiver.
608    ///
609    /// **Hint**: An NNF is a formula where negation is only applied to its atomic (including
610    /// equations) sub-formulae.
611    ///
612    /// **Example**:
613    /// ```rust
614    /// # use razor_fol::syntax::Formula;
615    ///
616    /// let formula: Formula = "not (P(x) iff Q(y))".parse().unwrap();
617    /// assert_eq!("(P(x) ∧ (¬Q(y))) ∨ ((¬P(x)) ∧ Q(y))", formula.nnf().to_string());
618    /// ```
619    pub fn nnf(&self) -> Formula {
620        match self {
621            Top | Bottom | Atom { .. } | Equals { .. } => self.clone(),
622            Not { ref formula } => {
623                match **formula {
624                    Top => Bottom,
625                    Bottom => Top,
626                    Atom { .. } | Equals { .. } => self.clone(),
627                    Not { ref formula } => *formula.clone(),
628                    And { ref left, ref right } => not(*left.clone())
629                        .nnf()
630                        .or(not(*right.clone())
631                            .nnf()),
632                    Or { ref left, ref right } => not(*left.clone())
633                        .nnf()
634                        .and(not(*right.clone())
635                            .nnf()),
636                    Implies { ref left, ref right } => left.nnf()
637                        .and(not(*right.clone())
638                            .nnf()),
639                    Iff { ref left, ref right } => left.nnf()
640                        .and(not(*right.clone())
641                            .nnf())
642                        .or(not(*left.clone())
643                            .nnf()
644                            .and(right.nnf())),
645                    Exists { ref variables, ref formula } => forall(
646                        variables.clone(),
647                        not(*formula.clone()).nnf(),
648                    ),
649                    Forall { ref variables, ref formula } => exists(
650                        variables.clone(),
651                        not(*formula.clone()).nnf(),
652                    ),
653                }
654            }
655            And { left, right } => left.nnf().and(right.nnf()),
656            Or { left, right } => left.nnf().or(right.nnf()),
657            Implies { left, right } => not(*left.clone())
658                .nnf()
659                .or(right.nnf()),
660            Iff { left, right } => not(*left.clone())
661                .nnf()
662                .or(right.nnf())
663                .and(left.nnf()
664                    .or(not(*right.clone())
665                        .nnf())),
666            Exists { variables, formula } => exists(
667                variables.clone(),
668                formula.nnf(),
669            ),
670            Forall { variables, formula } => forall(
671                variables.clone(),
672                formula.nnf(),
673            ),
674        }
675    }
676
677    /// Returns a Conjunctive Normal Form (CNF) equivalent to the receiver.
678    ///
679    /// **Hint**: A CNF is a formula that is a conjunction of zero or more clauses. A clause is a
680    /// disjunction of atomic formulae (including equations).
681    ///
682    /// **Note**: All free variables are assumed to be universally quantified.
683    ///
684    /// **Example**:
685    /// ```rust
686    /// # use razor_fol::syntax::Formula;
687    ///
688    /// let formula: Formula = "P(x) <=> Q(y)".parse().unwrap();
689    /// assert_eq!("((¬P(x)) ∨ Q(y)) ∧ ((¬Q(y)) ∨ P(x))", formula.cnf().to_string());
690    /// ```
691    pub fn cnf(&self) -> Formula {
692        self.cnf_with(&mut SkolemGenerator::new())
693    }
694
695    /// Is similar to [`Formula::cnf`] but uses an existing [`SkolemGenerator`] to avoid collision
696    /// when generating Skolem function names (including Skolem constants).
697    ///
698    /// **Note**: The CNF transformation includes Skolemization.
699    ///
700    /// [`SkolemGenerator`]: ../transform/struct.SkolemGenerator.html
701    /// [`Formula::cnf`]: ./enum.Formula.html#method.cnf
702    ///
703    /// **Example**:
704    /// ```rust
705    /// # use razor_fol::syntax::Formula;
706    /// use razor_fol::transform::SkolemGenerator;
707    ///
708    /// let mut generator = SkolemGenerator::from("s%");
709    /// let formula: Formula = "exists x. ((forall y. P(y) & Q(x, y))  -> R(x))".parse().unwrap();
710    /// assert_eq!("((¬P(\'s%1)) ∨ (¬Q(\'s%0, \'s%1))) ∨ R(\'s%0)",
711    ///     formula.cnf_with(&mut generator).to_string());
712    /// ```
713    pub fn cnf_with(&self, generator: &mut SkolemGenerator) -> Formula {
714        // The following distributes conjunctions in the given formula. The function assumes that
715        // its input is an NNF.
716        fn distribute_or(formula: &Formula) -> Formula {
717            match formula {
718                Top | Bottom | Atom { .. } | Equals { .. } | Not { .. } => formula.clone(),
719                And { left, right } => distribute_or(left)
720                    .and(distribute_or(right)),
721                Or { left, right } => {
722                    let left = distribute_or(left);
723                    let right = distribute_or(right);
724                    if let And { left: l, right: r } = left {
725                        distribute_or(&l.or(right.clone()))
726                            .and(distribute_or(&r.or(right)))
727                    } else if let And { left: l, right: r } = right {
728                        distribute_or(&left.clone().or(*l)).and(
729                            distribute_or(&left.or(*r)))
730                    } else {
731                        left.or(right)
732                    }
733                }
734                Forall { variables, formula } => forall(
735                    variables.clone(),
736                    distribute_or(formula),
737                ),
738                _ => panic!("something is wrong: expecting a formula in negation normal form")
739            }
740        }
741
742        // The following eliminates the existential quantifiers of the input formula.
743        fn remove_forall(formula: Formula) -> Formula {
744            if let Forall { formula, .. } = formula {
745                remove_forall(*formula)
746            } else {
747                formula
748            }
749        }
750
751        let nnf = self.snf_with(generator).nnf();
752        remove_forall(distribute_or(&nnf))
753    }
754
755    /// Returns a Disjunctive Normal Form (DNF) equivalent to the receiver.
756    ///
757    /// **Hint**: A DNF is a formula that is a disjunction of zero or more conjuncts. A conjunct
758    /// is a conjunction of atomic formulae (including equations).
759    ///
760    /// **Note**: All of the free variables are assumed to be universally quantified.
761    ///
762    /// **Example**:
763    /// ```rust
764    /// # use razor_fol::syntax::Formula;
765    ///
766    /// let formula: Formula = "P(x) iff Q(y)".parse().unwrap();
767    /// assert_eq!("(((¬P(x)) ∧ (¬Q(y))) ∨ ((¬P(x)) ∧ P(x))) ∨ ((Q(y) ∧ (¬Q(y))) ∨ (Q(y) ∧ P(x)))",
768    ///     formula.dnf().to_string());
769    /// ```
770    pub fn dnf(&self) -> Formula {
771        self.dnf_with(&mut SkolemGenerator::new())
772    }
773
774    /// Is similar to [`Formula::dnf`] but uses an existing [`SkolemGenerator`] to avoid collision
775    /// when generating Skolem function names (including Skolem constants).
776    ///
777    /// **Note**: The DNF transformation includes Skolemization.
778    ///
779    /// [`SkolemGenerator`]: ../transform/struct.SkolemGenerator.html
780    /// [`Formula::dnf`]: ./enum.Formula.html#method.dnf
781    ///
782    /// **Example**:
783    /// ```rust
784    /// # use razor_fol::syntax::Formula;
785    /// use razor_fol::transform::SkolemGenerator;
786    ///
787    /// let mut generator = SkolemGenerator::from("s%");
788    /// let formula: Formula = "!y. (!x. (P(y, x) | Q(x)) -> Q(y))".parse().unwrap();
789    /// assert_eq!("((¬P(y, s%0(y))) ∧ (¬Q(s%0(y)))) ∨ Q(y)",
790    ///     formula.dnf_with(&mut generator).to_string());
791    /// ```
792    pub fn dnf_with(&self, generator: &mut SkolemGenerator) -> Formula {
793        // The following distributes disjunction in the given formula. The function assumes that
794        // its input is an NNF.
795        fn distribute_and(formula: &Formula) -> Formula {
796            match formula {
797                Top | Bottom | Atom { .. } | Equals { .. } | Not { .. } => formula.clone(),
798                Or { left, right } => distribute_and(left)
799                    .or(distribute_and(right)),
800                And { left, right } => {
801                    let left = distribute_and(left);
802                    let right = distribute_and(right);
803                    if let Or { left: l, right: r } = left {
804                        distribute_and(&l.and(right.clone()))
805                            .or(distribute_and(&r.and(right)))
806                    } else if let Or { left: l, right: r } = right {
807                        distribute_and(&left.clone().and(*l))
808                            .or(distribute_and(&left.and(*r)))
809                    } else {
810                        And { left: Box::new(left), right: Box::new(right) }
811                    }
812                }
813                Forall { variables, formula } => forall(
814                    variables.clone(),
815                    distribute_and(formula),
816                ),
817                _ => panic!("Something is wrong: expecting a formula in negation normal form.")
818            }
819        }
820
821        // The following eliminates the existential quantifiers of the input formula.
822        fn remove_forall(formula: Formula) -> Formula {
823            if let Forall { formula, .. } = formula {
824                remove_forall(*formula)
825            } else {
826                formula
827            }
828        }
829
830        let nnf = self.snf_with(generator).nnf();
831        remove_forall(distribute_and(&nnf))
832    }
833
834    /// Applies a number of syntactic transformations to simplify the receiver formula.
835    ///
836    /// **Example**:
837    /// ```rust
838    /// # use razor_fol::syntax::Formula;
839    ///
840    /// let formula: Formula = "not (not P())".parse().unwrap();
841    /// assert_eq!("P()", formula.simplify().to_string());
842    ///
843    /// let formula: Formula = "forall x. (P() and true) | (Q(x) or false)".parse().unwrap();
844    /// assert_eq!("∀ x. (P() ∨ Q(x))", formula.simplify().to_string());
845    /// ```
846    pub fn simplify(&self) -> Formula {
847        match self {
848            Top | Bottom | Atom { .. } | Equals { .. } => self.clone(),
849            Not { formula } => {
850                let formula = formula.simplify();
851                match formula {
852                    Top => Bottom,
853                    Bottom => Top,
854                    Not { formula } => formula.simplify(),
855                    _ => not(formula)
856                }
857            }
858            And { left, right } => {
859                let left = left.simplify();
860                let right = right.simplify();
861                if let Bottom = left {
862                    Bottom
863                } else if let Bottom = right {
864                    Bottom
865                } else if let Top = left {
866                    right
867                } else if let Top = right {
868                    left
869                } else {
870                    left.and(right)
871                }
872            }
873            Or { left, right } => {
874                let left = left.simplify();
875                let right = right.simplify();
876                if let Top = left {
877                    Top
878                } else if let Top = right {
879                    Top
880                } else if let Bottom = left {
881                    right
882                } else if let Bottom = right {
883                    left
884                } else {
885                    left.or(right)
886                }
887            }
888            Implies { left, right } => {
889                let left = left.simplify();
890                let right = right.simplify();
891                if let Bottom = left {
892                    Top
893                } else if let Top = right {
894                    Top
895                } else if let Top = left {
896                    right
897                } else if let Bottom = right {
898                    not(left).simplify()
899                } else {
900                    left.implies(right)
901                }
902            }
903            Iff { left, right } => {
904                let left = left.simplify();
905                let right = right.simplify();
906                if let Top = left {
907                    right
908                } else if let Top = right {
909                    left
910                } else if let Bottom = left {
911                    not(right).simplify()
912                } else if let Bottom = right {
913                    not(left).simplify()
914                } else {
915                    left.iff(right)
916                }
917            }
918            Exists { variables, formula } => {
919                let formula = formula.simplify();
920                let free_vars = formula.free_vars();
921                let vs: Vec<V> = free_vars.iter()
922                    .filter(|v| variables.contains(v))
923                    .map(|v| (*v).clone())
924                    .collect();
925                if vs.is_empty() {
926                    formula
927                } else {
928                    exists(vs, formula)
929                }
930            }
931            Forall { variables, formula } => {
932                let formula = formula.simplify();
933                let free_vars = formula.free_vars();
934                let vs: Vec<V> = free_vars.iter()
935                    .filter(|v| variables.contains(v))
936                    .map(|v| (*v).clone())
937                    .collect();
938                if vs.is_empty() {
939                    formula
940                } else {
941                    forall(vs, formula)
942                }
943            }
944        }
945    }
946
947    /// Returns a list of formulae in [Geometric Normal Form][gnf] (GNF), equivalent to the
948    /// receiver.
949    ///
950    /// [gnf]: ../../chase/index.html#background
951    ///
952    /// **Hint**: For mor information about GNF, see [Geometric Logic in Computer Science][glics]
953    /// by Steve Vickers.
954    ///
955    /// [glics]: https://www.cs.bham.ac.uk/~sjv/GLiCS.pdf
956    ///
957    /// **Example**:
958    /// ```rust
959    /// # use razor_fol::syntax::Formula;
960    ///
961    /// let formula: Formula = "P(x) & (Q(x) | R(x))".parse().unwrap();
962    /// let gnf_to_string: Vec<String> = formula.gnf().iter().map(|f| f.to_string()).collect();
963    /// assert_eq!(vec!["⊤ → P(x)", "⊤ → (Q(x) ∨ R(x))"], gnf_to_string);
964    /// ```
965    pub fn gnf(&self) -> Vec<Formula> {
966        self.gnf_with(&mut SkolemGenerator::new())
967    }
968
969    /// Is similar to [`Formula::gnf`] but uses an existing [`SkolemGenerator`] to avoid collision
970    /// when generating Skolem function names (including Skolem constants).
971    ///
972    /// **Note**: The GNF transformation includes Skolemization.
973    ///
974    /// [`SkolemGenerator`]: ../transform/struct.SkolemGenerator.html
975    /// [`Formula::gnf`]: ./enum.Formula.html#method.gnf
976    ///
977    /// **Example**:
978    /// ```rust
979    /// # use razor_fol::syntax::Formula;
980    /// use razor_fol::transform::SkolemGenerator;
981    ///
982    /// let mut generator = SkolemGenerator::from("s%");
983    /// let formula: Formula = "P(y) -> exists x. P(x) & Q(y)".parse().unwrap();
984    /// let gnf_to_string: Vec<String> = formula.gnf().iter().map(|f| f.to_string()).collect();
985    /// assert_eq!(vec!["P(y) → P(sk#0(y))", "P(y) → Q(y)"], gnf_to_string);
986    /// ```
987    pub fn gnf_with(&self, generator: &mut SkolemGenerator) -> Vec<Formula> {
988        // For any disjunct of the CNF, the negative literals form the body of the geometric form
989        // and the positive literals form its head:
990        fn split_sides(disjunct: Formula) -> (Vec<Formula>, Vec<Formula>) {
991            match disjunct {
992                Or { left, right } => {
993                    let (mut left_body, mut left_head) = split_sides(*left);
994                    let (mut right_body, mut right_head) = split_sides(*right);
995
996                    left_body.append(&mut right_body);
997                    let body: Vec<Formula> = left_body.into_iter().unique().collect();
998
999                    left_head.append(&mut right_head);
1000                    let head: Vec<Formula> = left_head.into_iter().unique().collect();
1001
1002                    (body, head)
1003                }
1004                Not { formula } => (vec![*formula], vec![]),
1005                _ => (vec![], vec![disjunct])
1006            }
1007        }
1008
1009        // Convert the disjuncts of the CNF to an implication. These implications are geometric sequents.
1010        fn to_implication(disjunct: Formula) -> Formula {
1011            let (body, head) = split_sides(disjunct);
1012            let body = body
1013                .into_iter()
1014                .fold(Top, |x, y| x.and(y))
1015                .simplify();
1016            let head = head
1017                .into_iter()
1018                .fold(Bottom, |x, y| x.or(y))
1019                .simplify();
1020            body.implies(head)
1021        }
1022
1023        // Split the CNF to a set of disjuncts.
1024        fn get_disjuncts(cnf: Formula) -> Vec<Formula> {
1025            match cnf {
1026                And { left, right } => {
1027                    let mut left = get_disjuncts(*left);
1028                    let mut right = get_disjuncts(*right);
1029                    left.append(&mut right);
1030                    left.into_iter().unique().collect()
1031                }
1032                _ => vec![cnf]
1033            }
1034        }
1035
1036        get_disjuncts(self.cnf_with(generator))
1037            .into_iter()
1038            .map(to_implication)
1039            .collect()
1040    }
1041}
1042
1043impl Theory {
1044    /// Transforms the given theory to a *geometric theory*, where all formulae are in
1045    /// [Geometric Normal Form][gnf] (GNF).
1046    ///
1047    /// [gnf]: ../../chase/index.html#background
1048    ///
1049    /// **Hint**: For mor information about GNF, see [Geometric Logic in Computer Science][glics]
1050    /// by Steve Vickers.
1051    ///
1052    /// [glics]: https://www.cs.bham.ac.uk/~sjv/GLiCS.pdf
1053    ///
1054    /// **Example**:
1055    /// ```rust
1056    /// # use razor_fol::syntax::Theory;
1057    ///
1058    /// let theory: Theory = r#"
1059    ///     not P(x) or Q(x);
1060    ///     Q(x) -> exists y. P(x, y);
1061    /// "#.parse().unwrap();
1062    /// assert_eq!(r#"P(x) → Q(x)
1063    /// Q(x) → P(x, sk#0(x))"#, theory.gnf().to_string());
1064    /// ```
1065    pub fn gnf(&self) -> Theory {
1066        let mut generator = SkolemGenerator::new();
1067        let formulae: Vec<Formula> = self.formulae
1068            .iter()
1069            .flat_map(|f| f.gnf_with(&mut generator))
1070            .collect();
1071        Theory::from(compress_geometric(formulae))
1072    }
1073}
1074
1075// a helper to merge sequents with syntactically identical bodies
1076fn compress_geometric(formulae: Vec<Formula>) -> Vec<Formula> {
1077    formulae.into_iter().sorted_by(|f1, f2| { // sort sequents by their body
1078        match (f1, f2) {
1079            (Implies { left: f1, .. }, Implies { left: f2, .. }) => f1.cmp(f2),
1080            _ => Equal
1081        }
1082    }).into_iter().coalesce(|f1, f2| { // merge the ones with the same body:
1083        match f1 {
1084            Implies { left: ref l1, right: ref r1 } => {
1085                let l_vars = l1.free_vars();
1086                let r_vars = r1.free_vars();
1087                // compress sequents with no free variables that show up only in head:
1088                if r_vars.iter().all(|rv| l_vars
1089                    .iter()
1090                    .any(|lv| lv == rv)) {
1091                    match f2 {
1092                        Implies { left: ref l2, right: ref r2 } => {
1093                            let l_vars = l2.free_vars();
1094                            let r_vars = r2.free_vars();
1095                            if r_vars.iter().all(|rv| l_vars
1096                                .iter()
1097                                .any(|lv| lv == rv)) {
1098                                if l1 == l2 {
1099                                    Ok(l2.clone().implies(r1.clone().and(*r2.clone())))
1100                                } else {
1101                                    Err((f1, f2))
1102                                }
1103                            } else {
1104                                Err((f2, f1))
1105                            }
1106                        }
1107                        _ => Err((f2, f1))
1108                    }
1109                } else {
1110                    Err((f1, f2))
1111                }
1112            }
1113            _ => Err((f1, f2))
1114        }
1115    }).map(|f| { // convert the head to dnf and simplify it:
1116        match f {
1117            Implies { left, right: r } => left.implies(simplify_dnf(r.dnf())),
1118            _ => f
1119        }
1120    }).collect()
1121}
1122
1123// Simplifies the given DNF as a helper for compress geometric.
1124fn simplify_dnf(formula: Formula) -> Formula {
1125    fn disjunct_list(formula: Formula) -> Vec<Formula> {
1126        match formula {
1127            Or { left, right } => {
1128                let mut lefts = disjunct_list(*left);
1129                let mut rights = disjunct_list(*right);
1130                lefts.append(&mut rights);
1131                lefts
1132            }
1133            _ => vec![formula],
1134        }
1135    }
1136
1137    fn conjunct_list(formula: Formula) -> Vec<Formula> {
1138        match formula {
1139            And { left, right } => {
1140                let mut lefts = conjunct_list(*left);
1141                let mut rights = conjunct_list(*right);
1142                lefts.append(&mut rights);
1143                lefts
1144            }
1145            _ => vec![formula],
1146        }
1147    }
1148
1149    let disjuncts: Vec<Vec<Formula>> = disjunct_list(formula)
1150        .into_iter()
1151        .map(|d| conjunct_list(d)
1152            .into_iter()
1153            .unique()
1154            .collect())
1155        .collect();
1156
1157    let disjuncts: Vec<Vec<Formula>> = disjuncts
1158        .iter()
1159        .filter(|d| !disjuncts
1160            .iter()
1161            .any(|dd| (dd.len() < d.len() || (dd.len() == d.len() && dd < d))
1162                && dd
1163                .iter()
1164                .all(|cc| d
1165                    .iter()
1166                    .any(|c| cc == c)
1167                )
1168            )
1169        ).map(|d| d.clone())
1170        .unique()
1171        .collect();
1172
1173    disjuncts
1174        .into_iter()
1175        .map(|d| d
1176            .into_iter()
1177            .fold1(|f1, f2| f1.and(f2))
1178            .unwrap())
1179        .fold1(|f1, f2| f1.or(f2))
1180        .unwrap()
1181}
1182
1183#[cfg(test)]
1184mod test_transform {
1185    use super::*;
1186    use crate::test_prelude::*;
1187    use std::collections::HashMap;
1188
1189    #[test]
1190    fn test_substitution_map() {
1191        {
1192            let map: HashMap<&V, Term> = HashMap::new();
1193            assert_eq!(x(), x().substitute(&map));
1194        }
1195        {
1196            let mut map: HashMap<&V, Term> = HashMap::new();
1197            let x_v = &_x();
1198            let y_var = y();
1199
1200            map.insert(x_v, y_var);
1201            assert_eq!(y(), x().substitute(&map));
1202        }
1203        {
1204            let mut map: HashMap<&V, Term> = HashMap::new();
1205            let x_v = &_x();
1206            let y_v = &_y();
1207            let term_1 = g().app1(z());
1208            let term_2 = h().app2(z(), y());
1209
1210            map.insert(x_v, term_1);
1211            map.insert(y_v, term_2);
1212            assert_eq!(f().app2(g().app1(z()), h().app2(z(), y())),
1213                       f().app2(x(), y()).substitute(&map));
1214        }
1215    }
1216
1217    #[test]
1218    fn test_rename_term() {
1219        assert_eq!(x(), x().rename_vars(&|v: &V| v.clone()));
1220        assert_eq!(y(), x().rename_vars(&|v: &V| {
1221            if *v == _x() {
1222                _y()
1223            } else {
1224                v.clone()
1225            }
1226        }));
1227        assert_eq!(x(), x().rename_vars(&|v: &V| {
1228            if *v == _y() {
1229                _z()
1230            } else {
1231                v.clone()
1232            }
1233        }));
1234        assert_eq!(f().app1(y()), f().app1(x()).rename_vars(&|v: &V| {
1235            if *v == _x() {
1236                _y()
1237            } else {
1238                v.clone()
1239            }
1240        }));
1241        assert_eq!(f().app1(x()), f().app1(x()).rename_vars(&|v: &V| {
1242            if *v == _z() {
1243                _y()
1244            } else {
1245                v.clone()
1246            }
1247        }));
1248        assert_eq!(f().app2(z(), z()), f().app2(x(), y()).rename_vars(&|v: &V| {
1249            if *v == _x() {
1250                _z()
1251            } else if *v == _y() {
1252                _z()
1253            } else {
1254                v.clone()
1255            }
1256        }));
1257        assert_eq!(f().app2(y(), g().app2(y(), h().app1(z()))),
1258                   f().app2(x(), g().app2(x(), h().app1(y()))).rename_vars(&|v: &V| {
1259                       if *v == _x() {
1260                           _y()
1261                       } else if *v == _y() {
1262                           _z()
1263                       } else {
1264                           v.clone()
1265                       }
1266                   }));
1267    }
1268
1269    #[test]
1270    fn test_substitute_term() {
1271        assert_eq!(x(), x().substitute(&|v: &V| v.clone().into()));
1272        assert_eq!(a(), a().substitute(&|v: &V| {
1273            if *v == _x() {
1274                y()
1275            } else {
1276                v.clone().into()
1277            }
1278        }));
1279        assert_eq!(y(), x().substitute(&|v: &V| {
1280            if *v == _x() {
1281                y()
1282            } else {
1283                v.clone().into()
1284            }
1285        }));
1286        assert_eq!(a(), x().substitute(&|v: &V| {
1287            if *v == _x() {
1288                a()
1289            } else {
1290                v.clone().into()
1291            }
1292        }));
1293        assert_eq!(f().app1(z()), x().substitute(&|v: &V| {
1294            if *v == _x() {
1295                f().app1(z())
1296            } else {
1297                v.clone().into()
1298            }
1299        }));
1300        assert_eq!(x(), x().substitute(&|v: &V| {
1301            if *v == _y() {
1302                z()
1303            } else {
1304                v.clone().into()
1305            }
1306        }));
1307        assert_eq!(f().app1(y()), f().app1(x()).substitute(&|v: &V| {
1308            if *v == _x() {
1309                y()
1310            } else {
1311                v.clone().into()
1312            }
1313        }));
1314        assert_eq!(f().app1(g().app1(h().app2(y(), z()))), f().app1(x()).substitute(&|v: &V| {
1315            if *v == _x() {
1316                g().app1(h().app2(y(), z()))
1317            } else {
1318                v.clone().into()
1319            }
1320        }));
1321        assert_eq!(f().app1(x()), f().app1(x()).substitute(&|v: &V| {
1322            if *v == _y() {
1323                z()
1324            } else {
1325                v.clone().into()
1326            }
1327        }));
1328        assert_eq!(f().app2(g().app1(z()), h().app2(z(), y())),
1329                   f().app2(x(), y()).substitute(&|v: &V| {
1330                       if *v == _x() {
1331                           g().app1(z())
1332                       } else if *v == _y() {
1333                           h().app2(z(), y())
1334                       } else {
1335                           v.clone().into()
1336                       }
1337                   }));
1338        assert_eq!(f().app2(f().app1(f().app0()), g().app2(f().app1(f().app0()), h().app1(z()))),
1339                   f().app2(x(), g().app2(x(), h().app1(y()))).substitute(&|v: &V| {
1340                       if *v == _x() {
1341                           f().app1(f().app0())
1342                       } else if *v == _y() {
1343                           z()
1344                       } else {
1345                           v.clone().into()
1346                       }
1347                   }));
1348        assert_eq!(f().app2(f().app1(a()), g().app2(f().app1(a()), h().app1(z()))),
1349                   f().app2(x(), g().app2(x(), h().app1(y()))).substitute(&|v: &V| {
1350                       if *v == _x() {
1351                           f().app1(a())
1352                       } else if *v == _y() {
1353                           z()
1354                       } else {
1355                           v.clone().into()
1356                       }
1357                   }));
1358    }
1359
1360    #[test]
1361    fn test_skolem_generator() {
1362        assert_eq!(SkolemGenerator { prefix: "sk#".to_owned(), index: 0 }, SkolemGenerator::new());
1363        {
1364            let mut gen = SkolemGenerator::new();
1365            assert_eq!("sk#0", gen.next());
1366            assert_eq!("sk#1", gen.next());
1367            assert_eq!("sk#2", gen.next());
1368        }
1369        {
1370            let mut gen = SkolemGenerator::from("razor");
1371            assert_eq!("razor0", gen.next());
1372            assert_eq!("razor1", gen.next());
1373            assert_eq!("razor2", gen.next());
1374        }
1375    }
1376
1377    #[test]
1378    fn test_rename_formula() {
1379        assert_eq!(Top, Top.rename_vars(&|v: &V| {
1380            if *v == _x() {
1381                _y()
1382            } else {
1383                v.clone()
1384            }
1385        }));
1386        assert_eq!(Bottom, Bottom.rename_vars(&|v: &V| {
1387            if *v == _x() {
1388                _y()
1389            } else {
1390                v.clone()
1391            }
1392        }));
1393        assert_eq!(z().equals(z()), x().equals(y()).rename_vars(&|v: &V| {
1394            if *v == _x() {
1395                _z()
1396            } else if *v == _y() {
1397                _z()
1398            } else {
1399                v.clone()
1400            }
1401        }));
1402        assert_eq!(P().app1(x()), P().app1(x()).rename_vars(&|v: &V| {
1403            if *v == _x() {
1404                _x()
1405            } else {
1406                v.clone()
1407            }
1408        }));
1409        assert_eq!(P().app1(y()), P().app1(x()).rename_vars(&|v: &V| {
1410            if *v == _x() {
1411                _y()
1412            } else {
1413                v.clone()
1414            }
1415        }));
1416        assert_eq!(P().app3(y(), z(), y()), P().app3(x(), y(), x()).rename_vars(&|v: &V| {
1417            if *v == _x() {
1418                _y()
1419            } else if *v == _y() {
1420                _z()
1421            } else {
1422                v.clone()
1423            }
1424        }));
1425        assert_eq!(not(P().app3(y(), z(), y())), not(P().app3(x(), y(), x())).rename_vars(&|v: &V| {
1426            if *v == _x() {
1427                _y()
1428            } else if *v == _y() {
1429                _z()
1430            } else {
1431                v.clone()
1432            }
1433        }));
1434        assert_eq!(P().app1(z()).and(Q().app1(z())), P().app1(x()).and(Q().app1(y())).rename_vars(&|v: &V| {
1435            if *v == _x() {
1436                _z()
1437            } else if *v == _y() {
1438                _z()
1439            } else {
1440                v.clone()
1441            }
1442        }));
1443        assert_eq!(P().app1(z()).or(Q().app1(z())), P().app1(x()).or(Q().app1(y())).rename_vars(&|v: &V| {
1444            if *v == _x() {
1445                _z()
1446            } else if *v == _y() {
1447                _z()
1448            } else {
1449                v.clone()
1450            }
1451        }));
1452        assert_eq!(P().app1(z()).implies(Q().app1(z())), P().app1(x()).implies(Q().app1(y())).rename_vars(&|v: &V| {
1453            if *v == _x() {
1454                _z()
1455            } else if *v == _y() {
1456                _z()
1457            } else {
1458                v.clone()
1459            }
1460        }));
1461        assert_eq!(P().app1(z()).iff(Q().app1(z())), P().app1(x()).iff(Q().app1(y())).rename_vars(&|v: &V| {
1462            if *v == _x() {
1463                _z()
1464            } else if *v == _y() {
1465                _z()
1466            } else {
1467                v.clone()
1468            }
1469        }));
1470        assert_eq!(exists2(_x(), _y(), P().app3(y(), y(), y())),
1471                   exists2(_x(), _y(), P().app3(x(), y(), z())).rename_vars(&|v: &V| {
1472                       if *v == _x() {
1473                           _y()
1474                       } else if *v == _z() {
1475                           _y()
1476                       } else {
1477                           v.clone()
1478                       }
1479                   }));
1480        assert_eq!(forall2(_x(), _y(), P().app3(y(), y(), y())),
1481                   forall2(_x(), _y(), P().app3(x(), y(), z())).rename_vars(&|v: &V| {
1482                       if *v == _x() {
1483                           _y()
1484                       } else if *v == _z() {
1485                           _y()
1486                       } else {
1487                           v.clone()
1488                       }
1489                   }));
1490        assert_eq!(
1491            exists1(_x(),
1492                    forall1(_y(),
1493                            P().app1(y()).or(Q().app1(z()).and(R().app1(z()))),
1494                    ).and(not(z().equals(z())))),
1495            exists1(_x(),
1496                    forall1(_y(),
1497                            P().app1(x()).or(Q().app1(y()).and(R().app1(z()))),
1498                    ).and(not(y().equals(y()))),
1499            ).rename_vars(&|v: &V| {
1500                if *v == _x() {
1501                    _y()
1502                } else if *v == _y() {
1503                    _z()
1504                } else {
1505                    v.clone()
1506                }
1507            }));
1508    }
1509
1510
1511    #[test]
1512    fn test_substitute_formula() {
1513        assert_eq!(Top, Top.substitute(&|v: &V| {
1514            if *v == _x() {
1515                y()
1516            } else {
1517                v.clone().into()
1518            }
1519        }));
1520        assert_eq!(Bottom, Bottom.substitute(&|v: &V| {
1521            if *v == _x() {
1522                y()
1523            } else {
1524                v.clone().into()
1525            }
1526        }));
1527        assert_eq!(f().app1(g().app1(z())).equals(g().app1(f().app1(z()))), x().equals(y()).substitute(&|v: &V| {
1528            if *v == _x() {
1529                f().app1(g().app1(z()))
1530            } else if *v == _y() {
1531                g().app1(f().app1(z()))
1532            } else {
1533                v.clone().into()
1534            }
1535        }));
1536        assert_eq!(P().app1(h().app1(y())), P().app1(x()).substitute(&|v: &V| {
1537            if *v == _x() {
1538                h().app1(y())
1539            } else {
1540                v.clone().into()
1541            }
1542        }));
1543        assert_eq!(P().app1(g().app1(g().app1(x()))), P().app1(x()).substitute(&|v: &V| {
1544            if *v == _x() {
1545                g().app1(g().app1(x()))
1546            } else {
1547                v.clone().into()
1548            }
1549        }));
1550        assert_eq!(P().app3(y(), f().app1(z()), y()),
1551                   P().app3(x(), y(), x()).substitute(&|v: &V| {
1552                       if *v == _x() {
1553                           y()
1554                       } else if *v == _y() {
1555                           f().app1(z())
1556                       } else {
1557                           v.clone().into()
1558                       }
1559                   }));
1560        assert_eq!(not(P().app3(h().app0(), z(), h().app0())),
1561                   not(P().app3(x(), y(), x())).substitute(&|v: &V| {
1562                       if *v == _x() {
1563                           h().app0()
1564                       } else if *v == _y() {
1565                           z()
1566                       } else {
1567                           v.clone().into()
1568                       }
1569                   }));
1570        assert_eq!(P().app1(f().app1(g().app0())).and(Q().app1(h().app1(z()))),
1571                   P().app1(x()).and(Q().app1(y())).substitute(&|v: &V| {
1572                       if *v == _x() {
1573                           f().app1(g().app0())
1574                       } else if *v == _y() {
1575                           h().app1(z())
1576                       } else {
1577                           v.clone().into()
1578                       }
1579                   }));
1580        assert_eq!(P().app1(f().app1(g().app0())).or(Q().app1(h().app1(z()))),
1581                   P().app1(x()).or(Q().app1(y())).substitute(&|v: &V| {
1582                       if *v == _x() {
1583                           f().app1(g().app0())
1584                       } else if *v == _y() {
1585                           h().app1(z())
1586                       } else {
1587                           v.clone().into()
1588                       }
1589                   }));
1590        assert_eq!(P().app1(f().app0()).implies(Q().app1(g().app0())),
1591                   P().app1(x()).implies(Q().app1(y())).substitute(&|v: &V| {
1592                       if *v == _x() {
1593                           f().app0()
1594                       } else if *v == _y() {
1595                           g().app0()
1596                       } else {
1597                           v.clone().into()
1598                       }
1599                   }));
1600        assert_eq!(P().app1(a()).implies(Q().app1(b())),
1601                   P().app1(x()).implies(Q().app1(y())).substitute(&|v: &V| {
1602                       if *v == _x() {
1603                           a()
1604                       } else if *v == _y() {
1605                           b()
1606                       } else {
1607                           v.clone().into()
1608                       }
1609                   }));
1610        assert_eq!(P().app1(f().app0()).iff(Q().app1(g().app0())),
1611                   P().app1(x()).iff(Q().app1(y())).substitute(&|v: &V| {
1612                       if *v == _x() {
1613                           f().app0()
1614                       } else if *v == _y() {
1615                           g().app0()
1616                       } else {
1617                           v.clone().into()
1618                       }
1619                   }));
1620        assert_eq!(P().app1(a()).iff(Q().app1(b())),
1621                   P().app1(x()).iff(Q().app1(y())).substitute(&|v: &V| {
1622                       if *v == _x() {
1623                           a()
1624                       } else if *v == _y() {
1625                           b()
1626                       } else {
1627                           v.clone().into()
1628                       }
1629                   }));
1630        assert_eq!(exists2(_x(), _y(), P().app3(f().app1(g().app1(y())), y(), y())),
1631                   exists2(_x(), _y(), P().app3(x(), y(), z())).substitute(&|v: &V| {
1632                       if *v == _x() {
1633                           f().app1(g().app1(y()))
1634                       } else if *v == _z() {
1635                           y()
1636                       } else {
1637                           v.clone().into()
1638                       }
1639                   }));
1640        assert_eq!(forall2(_x(), _y(), P().app3(f().app1(g().app1(y())), y(), y())),
1641                   forall2(_x(), _y(), P().app3(x(), y(), z())).substitute(&|v: &V| {
1642                       if *v == _x() {
1643                           f().app1(g().app1(y()))
1644                       } else if *v == _z() {
1645                           y()
1646                       } else {
1647                           v.clone().into()
1648                       }
1649                   }));
1650        assert_eq!(
1651            exists1(_x(),
1652                    forall1(_y(),
1653                            P().app1(y()).or(Q().app1(z()).and(R().app1(z()))),
1654                    ).and(not(z().equals(z())))),
1655            exists1(_x(),
1656                    forall1(_y(),
1657                            P().app1(x()).or(Q().app1(y()).and(R().app1(z()))),
1658                    ).and(not(y().equals(y()))),
1659            ).substitute(&|v: &V| {
1660                if *v == _x() {
1661                    y()
1662                } else if *v == _y() {
1663                    z()
1664                } else {
1665                    v.clone().into()
1666                }
1667            }));
1668    }
1669
1670    #[test]
1671    fn test_pnf() {
1672        {
1673            let formula: Formula = "true".parse().unwrap();
1674            assert_debug_string("true", formula.pnf());
1675        }
1676        {
1677            let formula: Formula = "false".parse().unwrap();
1678            assert_debug_string("false", formula.pnf());
1679        }
1680        {
1681            let formula: Formula = "P(x)".parse().unwrap();
1682            assert_debug_string("P(x)", formula.pnf());
1683        }
1684        {
1685            let formula: Formula = "x = y".parse().unwrap();
1686            assert_debug_string("x = y", formula.pnf());
1687        }
1688        {
1689            let formula: Formula = "~P(x)".parse().unwrap();
1690            assert_debug_string("~P(x)", formula.pnf());
1691        }
1692        {
1693            let formula: Formula = "P(x) & Q(y)".parse().unwrap();
1694            assert_debug_string("P(x) & Q(y)", formula.pnf());
1695        }
1696        {
1697            let formula: Formula = "P(x) | Q(y)".parse().unwrap();
1698            assert_debug_string("P(x) | Q(y)", formula.pnf());
1699        }
1700        {
1701            let formula: Formula = "P(x) -> Q(y)".parse().unwrap();
1702            assert_debug_string("P(x) -> Q(y)", formula.pnf());
1703        }
1704        {
1705            let formula: Formula = "P(x) <=> Q(y)".parse().unwrap();
1706            assert_debug_string("(P(x) -> Q(y)) & (Q(y) -> P(x))", formula.pnf());
1707        }
1708        {
1709            let formula: Formula = "? x. P(x) & ~Q(y) | R(z)".parse().unwrap();
1710            assert_debug_string("? x. ((P(x) & (~Q(y))) | R(z))", formula.pnf());
1711        }
1712        {
1713            let formula: Formula = "! x. P(x) & ~Q(y) | R(z)".parse().unwrap();
1714            assert_debug_string("! x. ((P(x) & (~Q(y))) | R(z))", formula.pnf());
1715        }
1716        // sanity checking:
1717        {
1718            let formula: Formula = "~? x. P(x)".parse().unwrap();
1719            assert_debug_string("! x. (~P(x))", formula.pnf());
1720        }
1721        {
1722            let formula: Formula = "(! x. P(x)) & Q(y)".parse().unwrap();
1723            assert_debug_string("! x. (P(x) & Q(y))", formula.pnf());
1724        }
1725        {
1726            let formula: Formula = "(? x. P(x)) & Q(y)".parse().unwrap();
1727            assert_debug_string("? x. (P(x) & Q(y))", formula.pnf());
1728        }
1729        {
1730            let formula: Formula = "(! x. P(x)) & Q(x)".parse().unwrap();
1731            assert_debug_string("! x`. (P(x`) & Q(x))", formula.pnf());
1732        }
1733        {
1734            let formula: Formula = "(? x. P(x)) & Q(x)".parse().unwrap();
1735            assert_debug_string("? x`. (P(x`) & Q(x))", formula.pnf());
1736        }
1737        {
1738            let formula: Formula = "(! x, y. P(x, y)) & Q(x, y)".parse().unwrap();
1739            assert_debug_string("! x`, y`. (P(x`, y`) & Q(x, y))", formula.pnf());
1740        }
1741        {
1742            let formula: Formula = "(? x, y. P(x, y)) & Q(x, y)".parse().unwrap();
1743            assert_debug_string("? x`, y`. (P(x`, y`) & Q(x, y))", formula.pnf());
1744        }
1745        {
1746            let formula: Formula = "Q(y) & ! x. P(x)".parse().unwrap();
1747            assert_debug_string("! x. (Q(y) & P(x))", formula.pnf());
1748        }
1749        {
1750            let formula: Formula = "Q(y) & ? x. P(x)".parse().unwrap();
1751            assert_debug_string("? x. (Q(y) & P(x))", formula.pnf());
1752        }
1753        {
1754            let formula: Formula = "Q(x) & ! x. P(x)".parse().unwrap();
1755            assert_debug_string("! x`. (Q(x) & P(x`))", formula.pnf());
1756        }
1757        {
1758            let formula: Formula = "Q(x) & ? x. P(x)".parse().unwrap();
1759            assert_debug_string("? x`. (Q(x) & P(x`))", formula.pnf());
1760        }
1761        {
1762            let formula: Formula = "Q(x, y) & ! x, y. P(x, y)".parse().unwrap();
1763            assert_debug_string("! x`, y`. (Q(x, y) & P(x`, y`))", formula.pnf());
1764        }
1765        {
1766            let formula: Formula = "Q(x, y) & ? x, y. P(x, y)".parse().unwrap();
1767            assert_debug_string("? x`, y`. (Q(x, y) & P(x`, y`))", formula.pnf());
1768        }
1769        {
1770            let formula: Formula = "(! x. P(x)) | Q(y)".parse().unwrap();
1771            assert_debug_string("! x. (P(x) | Q(y))", formula.pnf());
1772        }
1773        {
1774            let formula: Formula = "(? x. P(x)) | Q(y)".parse().unwrap();
1775            assert_debug_string("? x. (P(x) | Q(y))", formula.pnf());
1776        }
1777        {
1778            let formula: Formula = "(! x. P(x)) | Q(x)".parse().unwrap();
1779            assert_debug_string("! x`. (P(x`) | Q(x))", formula.pnf());
1780        }
1781        {
1782            let formula: Formula = "(? x. P(x)) | Q(x)".parse().unwrap();
1783            assert_debug_string("? x`. (P(x`) | Q(x))", formula.pnf());
1784        }
1785        {
1786            let formula: Formula = "(! x, y. P(x, y)) | Q(x, y)".parse().unwrap();
1787            assert_debug_string("! x`, y`. (P(x`, y`) | Q(x, y))", formula.pnf());
1788        }
1789        {
1790            let formula: Formula = "(? x, y. P(x, y)) | Q(x, y)".parse().unwrap();
1791            assert_debug_string("? x`, y`. (P(x`, y`) | Q(x, y))", formula.pnf());
1792        }
1793        {
1794            let formula: Formula = "Q(y) | ! x. P(x)".parse().unwrap();
1795            assert_debug_string("! x. (Q(y) | P(x))", formula.pnf());
1796        }
1797        {
1798            let formula: Formula = "Q(y) | ? x. P(x)".parse().unwrap();
1799            assert_debug_string("? x. (Q(y) | P(x))", formula.pnf());
1800        }
1801        {
1802            let formula: Formula = "Q(x) | ! x. P(x)".parse().unwrap();
1803            assert_debug_string("! x`. (Q(x) | P(x`))", formula.pnf());
1804        }
1805        {
1806            let formula: Formula = "Q(x) | ? x. P(x)".parse().unwrap();
1807            assert_debug_string("? x`. (Q(x) | P(x`))", formula.pnf());
1808        }
1809        {
1810            let formula: Formula = "Q(x, y) | ! x, y. P(x, y)".parse().unwrap();
1811            assert_debug_string("! x`, y`. (Q(x, y) | P(x`, y`))", formula.pnf());
1812        }
1813        {
1814            let formula: Formula = "Q(x, y) | ? x, y. P(x, y)".parse().unwrap();
1815            assert_debug_string("? x`, y`. (Q(x, y) | P(x`, y`))", formula.pnf());
1816        }
1817        {
1818            let formula: Formula = "(! x. P(x)) -> Q(y)".parse().unwrap();
1819            assert_debug_string("? x. (P(x) -> Q(y))", formula.pnf());
1820        }
1821        {
1822            let formula: Formula = "(? x. P(x)) -> Q(y)".parse().unwrap();
1823            assert_debug_string("! x. (P(x) -> Q(y))", formula.pnf());
1824        }
1825        {
1826            let formula: Formula = "(! x. P(x)) -> Q(x)".parse().unwrap();
1827            assert_debug_string("? x`. (P(x`) -> Q(x))", formula.pnf());
1828        }
1829        {
1830            let formula: Formula = "(? x. P(x)) -> Q(x)".parse().unwrap();
1831            assert_debug_string("! x`. (P(x`) -> Q(x))", formula.pnf());
1832        }
1833        {
1834            let formula: Formula = "(! x, y. P(x, y)) -> Q(x, y)".parse().unwrap();
1835            assert_debug_string("? x`, y`. (P(x`, y`) -> Q(x, y))", formula.pnf());
1836        }
1837        {
1838            let formula: Formula = "(? x, y. P(x, y)) -> Q(x, y)".parse().unwrap();
1839            assert_debug_string("! x`, y`. (P(x`, y`) -> Q(x, y))", formula.pnf());
1840        }
1841        {
1842            let formula: Formula = "Q(y) -> ! x. P(x)".parse().unwrap();
1843            assert_debug_string("! x. (Q(y) -> P(x))", formula.pnf());
1844        }
1845        {
1846            let formula: Formula = "Q(y) -> ? x. P(x)".parse().unwrap();
1847            assert_debug_string("? x. (Q(y) -> P(x))", formula.pnf());
1848        }
1849        {
1850            let formula: Formula = "Q(x) -> ! x. P(x)".parse().unwrap();
1851            assert_debug_string("! x`. (Q(x) -> P(x`))", formula.pnf());
1852        }
1853        {
1854            let formula: Formula = "Q(x) -> ? x. P(x)".parse().unwrap();
1855            assert_debug_string("? x`. (Q(x) -> P(x`))", formula.pnf());
1856        }
1857        {
1858            let formula: Formula = "Q(x, y) -> ! x, y. P(x, y)".parse().unwrap();
1859            assert_debug_string("! x`, y`. (Q(x, y) -> P(x`, y`))", formula.pnf());
1860        }
1861        {
1862            let formula: Formula = "Q(x, y) -> ? x, y. P(x, y)".parse().unwrap();
1863            assert_debug_string("? x`, y`. (Q(x, y) -> P(x`, y`))", formula.pnf());
1864        }
1865
1866        {
1867            let formula: Formula = "(! x. P(x)) <=> Q(y)".parse().unwrap();
1868            assert_debug_string("? x. (! x`. ((P(x) -> Q(y)) & (Q(y) -> P(x`))))",
1869                                formula.pnf());
1870        }
1871        {
1872            let formula: Formula = "(? x. P(x)) <=> Q(y)".parse().unwrap();
1873            assert_debug_string("! x. (? x`. ((P(x) -> Q(y)) & (Q(y) -> P(x`))))",
1874                                formula.pnf());
1875        }
1876        {
1877            let formula: Formula = "(! x. P(x)) <=> Q(x)".parse().unwrap();
1878            assert_debug_string("? x`. (! x``. ((P(x`) -> Q(x)) & (Q(x) -> P(x``))))",
1879                                formula.pnf());
1880        }
1881        {
1882            let formula: Formula = "(? x. P(x)) <=> Q(x)".parse().unwrap();
1883            assert_debug_string("! x`. (? x``. ((P(x`) -> Q(x)) & (Q(x) -> P(x``))))",
1884                                formula.pnf());
1885        }
1886        {
1887            let formula: Formula = "(! x, y. P(x, y)) <=> Q(x, y)".parse().unwrap();
1888            assert_debug_string("? x`, y`. (! x``, y``. ((P(x`, y`) -> Q(x, y)) & (Q(x, y) -> P(x``, y``))))",
1889                                formula.pnf());
1890        }
1891        {
1892            let formula: Formula = "(? x, y. P(x, y)) <=> Q(x, y)".parse().unwrap();
1893            assert_debug_string("! x`, y`. (? x``, y``. ((P(x`, y`) -> Q(x, y)) & (Q(x, y) -> P(x``, y``))))",
1894                                formula.pnf());
1895        }
1896        {
1897            let formula: Formula = "Q(y) <=> ! x. P(x)".parse().unwrap();
1898            assert_debug_string("! x. (? x`. ((Q(y) -> P(x)) & (P(x`) -> Q(y))))",
1899                                formula.pnf());
1900        }
1901        {
1902            let formula: Formula = "Q(y) <=> ? x. P(x)".parse().unwrap();
1903            assert_debug_string("? x. (! x`. ((Q(y) -> P(x)) & (P(x`) -> Q(y))))",
1904                                formula.pnf());
1905        }
1906        {
1907            let formula: Formula = "Q(x) <=> ! x. P(x)".parse().unwrap();
1908            assert_debug_string("! x`. (? x``. ((Q(x) -> P(x`)) & (P(x``) -> Q(x))))",
1909                                formula.pnf());
1910        }
1911        {
1912            let formula: Formula = "Q(x) <=> ? x. P(x)".parse().unwrap();
1913            assert_debug_string("? x`. (! x``. ((Q(x) -> P(x`)) & (P(x``) -> Q(x))))",
1914                                formula.pnf());
1915        }
1916        {
1917            let formula: Formula = "Q(x, y) <=> ! x, y. P(x, y)".parse().unwrap();
1918            assert_debug_string("! x`, y`. (? x``, y``. ((Q(x, y) -> P(x`, y`)) & (P(x``, y``) -> Q(x, y))))",
1919                                formula.pnf());
1920        }
1921        {
1922            let formula: Formula = "Q(x, y) <=> ? x, y. P(x, y)".parse().unwrap();
1923            assert_debug_string("? x`, y`. (! x``, y``. ((Q(x, y) -> P(x`, y`)) & (P(x``, y``) -> Q(x, y))))",
1924                                formula.pnf());
1925        }
1926        //renaming tests
1927        assert_debug_string("! x``, x`. (P(x``) & Q(x))",
1928                            forall2(_x(), _x_1(), P().app1(x())).and(Q().app1(x())).pnf());
1929        assert_debug_string("? x``, x`. (P(x``) & Q(x))",
1930                            exists2(_x(), _x_1(), P().app1(x())).and(Q().app1(x())).pnf());
1931        assert_debug_string("? x``. (P(x``) & Q(x, x`))",
1932                            exists1(_x(), P().app1(x())).and(Q().app2(x(), x_1())).pnf());
1933        assert_debug_string("? x``. (P(x``, x`) & Q(x))",
1934                            exists1(_x(), P().app2(x(), x_1())).and(Q().app1(x())).pnf());
1935        assert_debug_string("! x``, x`. (Q(x) & P(x``))",
1936                            Q().app1(x()).and(forall2(_x(), _x_1(), P().app1(x()))).pnf());
1937        assert_debug_string("? x``, x`. (Q(x) & P(x``))",
1938                            Q().app1(x()).and(exists2(_x(), _x_1(), P().app1(x()))).pnf());
1939        assert_debug_string("? x``. (Q(x, x`) & P(x``))",
1940                            Q().app2(x(), x_1()).and(exists1(_x(), P().app1(x()))).pnf());
1941        assert_debug_string("? x``. (Q(x) & P(x``, x`))",
1942                            Q().app1(x()).and(exists1(_x(), P().app2(x(), x_1()))).pnf());
1943
1944        assert_debug_string("! x``, x`. (P(x``) | Q(x))",
1945                            forall2(_x(), _x_1(), P().app1(x())).or(Q().app1(x())).pnf());
1946        assert_debug_string("? x``, x`. (P(x``) | Q(x))",
1947                            exists2(_x(), _x_1(), P().app1(x())).or(Q().app1(x())).pnf());
1948        assert_debug_string("? x``. (P(x``) | Q(x, x`))",
1949                            exists1(_x(), P().app1(x())).or(Q().app2(x(), x_1())).pnf());
1950        assert_debug_string("? x``. (P(x``, x`) | Q(x))",
1951                            exists1(_x(), P().app2(x(), x_1())).or(Q().app1(x())).pnf());
1952        assert_debug_string("! x``, x`. (Q(x) | P(x``))",
1953                            Q().app1(x()).or(forall2(_x(), _x_1(), P().app1(x()))).pnf());
1954        assert_debug_string("? x``, x`. (Q(x) | P(x``))",
1955                            Q().app1(x()).or(exists2(_x(), _x_1(), P().app1(x()))).pnf());
1956        assert_debug_string("? x``. (Q(x, x`) | P(x``))",
1957                            Q().app2(x(), x_1()).or(exists1(_x(), P().app1(x()))).pnf());
1958        assert_debug_string("? x``. (Q(x) | P(x``, x`))",
1959                            Q().app1(x()).or(exists1(_x(), P().app2(x(), x_1()))).pnf());
1960
1961        assert_debug_string("? x``, x`. (P(x``) -> Q(x))",
1962                            forall2(_x(), _x_1(), P().app1(x())).implies(Q().app1(x())).pnf());
1963        assert_debug_string("! x``, x`. (P(x``) -> Q(x))",
1964                            exists2(_x(), _x_1(), P().app1(x())).implies(Q().app1(x())).pnf());
1965        assert_debug_string("! x``. (P(x``) -> Q(x, x`))",
1966                            exists1(_x(), P().app1(x())).implies(Q().app2(x(), x_1())).pnf());
1967        assert_debug_string("! x``. (P(x``, x`) -> Q(x))",
1968                            exists1(_x(), P().app2(x(), x_1())).implies(Q().app1(x())).pnf());
1969        assert_debug_string("! x``, x`. (Q(x) -> P(x``))",
1970                            Q().app1(x()).implies(forall2(_x(), _x_1(), P().app1(x()))).pnf());
1971        assert_debug_string("? x``, x`. (Q(x) -> P(x``))",
1972                            Q().app1(x()).implies(exists2(_x(), _x_1(), P().app1(x()))).pnf());
1973        assert_debug_string("? x``. (Q(x, x`) -> P(x``))",
1974                            Q().app2(x(), x_1()).implies(exists1(_x(), P().app1(x()))).pnf());
1975        assert_debug_string("? x``. (Q(x) -> P(x``, x`))",
1976                            Q().app1(x()).implies(exists1(_x(), P().app2(x(), x_1()))).pnf());
1977
1978        assert_debug_string("? x``, x`. (! x```, x`. ((P(x``) -> Q(x)) & (Q(x) -> P(x```))))",
1979                            forall2(_x(), _x_1(), P().app1(x())).iff(Q().app1(x())).pnf());
1980        assert_debug_string("! x``, x`. (? x```, x`. ((P(x``) -> Q(x)) & (Q(x) -> P(x```))))",
1981                            exists2(_x(), _x_1(), P().app1(x())).iff(Q().app1(x())).pnf());
1982        assert_debug_string("! x``. (? x```. ((P(x``) -> Q(x, x`)) & (Q(x, x`) -> P(x```))))",
1983                            exists1(_x(), P().app1(x())).iff(Q().app2(x(), x_1())).pnf());
1984        assert_debug_string("! x``. (? x```. ((P(x``, x`) -> Q(x)) & (Q(x) -> P(x```, x`))))",
1985                            exists1(_x(), P().app2(x(), x_1())).iff(Q().app1(x())).pnf());
1986        assert_debug_string("! x``, x`. (? x```, x`. ((Q(x) -> P(x``)) & (P(x```) -> Q(x))))",
1987                            Q().app1(x()).iff(forall2(_x(), _x_1(), P().app1(x()))).pnf());
1988        assert_debug_string("? x``, x`. (! x```, x`. ((Q(x) -> P(x``)) & (P(x```) -> Q(x))))",
1989                            Q().app1(x()).iff(exists2(_x(), _x_1(), P().app1(x()))).pnf());
1990        assert_debug_string("? x``. (! x```. ((Q(x, x`) -> P(x``)) & (P(x```) -> Q(x, x`))))",
1991                            Q().app2(x(), x_1()).iff(exists1(_x(), P().app1(x()))).pnf());
1992        assert_debug_string("? x``. (! x```. ((Q(x) -> P(x``, x`)) & (P(x```, x`) -> Q(x))))",
1993                            Q().app1(x()).iff(exists1(_x(), P().app2(x(), x_1()))).pnf());
1994        // both sides of binary formulae
1995        {
1996            let formula: Formula = "(! x. P(x)) & (! x. Q(x))".parse().unwrap();
1997            assert_debug_string("! x. (! x`. (P(x) & Q(x`)))", formula.pnf());
1998        }
1999        {
2000            let formula: Formula = "(! x. P(x)) & (? x. Q(x))".parse().unwrap();
2001            assert_debug_string("! x. (? x`. (P(x) & Q(x`)))", formula.pnf());
2002        }
2003        {
2004            let formula: Formula = "(? x. P(x)) & (! x. Q(x))".parse().unwrap();
2005            assert_debug_string("? x. (! x`. (P(x) & Q(x`)))", formula.pnf());
2006        }
2007        {
2008            let formula: Formula = "(? x. P(x)) & (? x. Q(x))".parse().unwrap();
2009            assert_debug_string("? x. (? x`. (P(x) & Q(x`)))", formula.pnf());
2010        }
2011        {
2012            let formula: Formula = "(! x. P(x)) | (! x. Q(x))".parse().unwrap();
2013            assert_debug_string("! x. (! x`. (P(x) | Q(x`)))", formula.pnf());
2014        }
2015        {
2016            let formula: Formula = "(! x. P(x)) | (? x. Q(x))".parse().unwrap();
2017            assert_debug_string("! x. (? x`. (P(x) | Q(x`)))", formula.pnf());
2018        }
2019        {
2020            let formula: Formula = "(? x. P(x)) | (! x. Q(x))".parse().unwrap();
2021            assert_debug_string("? x. (! x`. (P(x) | Q(x`)))", formula.pnf());
2022        }
2023        {
2024            let formula: Formula = "(? x. P(x)) | (? x. Q(x))".parse().unwrap();
2025            assert_debug_string("? x. (? x`. (P(x) | Q(x`)))", formula.pnf());
2026        }
2027        {
2028            let formula: Formula = "(! x. P(x)) -> (! x. Q(x))".parse().unwrap();
2029            assert_debug_string("? x. (! x`. (P(x) -> Q(x`)))", formula.pnf());
2030        }
2031        {
2032            let formula: Formula = "(! x. P(x)) -> (? x. Q(x))".parse().unwrap();
2033            assert_debug_string("? x. (? x`. (P(x) -> Q(x`)))", formula.pnf());
2034        }
2035        {
2036            let formula: Formula = "(? x. P(x)) -> (! x. Q(x))".parse().unwrap();
2037            assert_debug_string("! x. (! x`. (P(x) -> Q(x`)))", formula.pnf());
2038        }
2039        {
2040            let formula: Formula = "(? x. P(x)) -> (? x. Q(x))".parse().unwrap();
2041            assert_debug_string("! x. (? x`. (P(x) -> Q(x`)))", formula.pnf());
2042        }
2043        {
2044            let formula: Formula = "(! x. P(x)) <=> (! x. Q(x))".parse().unwrap();
2045            assert_debug_string("? x. (! x`. (? x``. (! x```. ((P(x) -> Q(x`)) & (Q(x``) -> P(x```))))))",
2046                                formula.pnf());
2047        }
2048        {
2049            let formula: Formula = "(! x. P(x)) <=> (? x. Q(x))".parse().unwrap();
2050            assert_debug_string("? x. (? x`. (! x``. (! x```. ((P(x) -> Q(x`)) & (Q(x``) -> P(x```))))))",
2051                                formula.pnf());
2052        }
2053        {
2054            let formula: Formula = "(? x. P(x)) <=> (! x. Q(x))".parse().unwrap();
2055            assert_debug_string("! x. (! x`. (? x``. (? x```. ((P(x) -> Q(x`)) & (Q(x``) -> P(x```))))))",
2056                                formula.pnf());
2057        }
2058        {
2059            let formula: Formula = "(? x. P(x)) <=> (? x. Q(x))".parse().unwrap();
2060            assert_debug_string("! x. (? x`. (! x``. (? x```. ((P(x) -> Q(x`)) & (Q(x``) -> P(x```))))))",
2061                                formula.pnf());
2062        }
2063        // multiple steps
2064        {
2065            let formula: Formula = "~~?x.P(x)".parse().unwrap();
2066            assert_debug_string("? x. (~(~P(x)))", formula.pnf());
2067        }
2068        {
2069            let formula: Formula = "~~!x.P(x)".parse().unwrap();
2070            assert_debug_string("! x. (~(~P(x)))", formula.pnf());
2071        }
2072        {
2073            let formula: Formula = "P(x) & ((! x. Q(x)) & R(x))".parse().unwrap();
2074            assert_debug_string("! x`. (P(x) & (Q(x`) & R(x)))", formula.pnf());
2075        }
2076        {
2077            let formula: Formula = "P(x) & ((? x. Q(x)) & R(x))".parse().unwrap();
2078            assert_debug_string("? x`. (P(x) & (Q(x`) & R(x)))", formula.pnf());
2079        }
2080        {
2081            let formula: Formula = "P(x) | ((! x. Q(x)) | R(x))".parse().unwrap();
2082            assert_debug_string("! x`. (P(x) | (Q(x`) | R(x)))", formula.pnf());
2083        }
2084        {
2085            let formula: Formula = "P(x) | ((? x. Q(x)) | R(x))".parse().unwrap();
2086            assert_debug_string("? x`. (P(x) | (Q(x`) | R(x)))", formula.pnf());
2087        }
2088        {
2089            let formula: Formula = "P(x) -> ((! x. Q(x)) -> R(x))".parse().unwrap();
2090            assert_debug_string("? x`. (P(x) -> (Q(x`) -> R(x)))", formula.pnf());
2091        }
2092        {
2093            let formula: Formula = "P(x) -> ((? x. Q(x)) -> R(x))".parse().unwrap();
2094            assert_debug_string("! x`. (P(x) -> (Q(x`) -> R(x)))", formula.pnf());
2095        }
2096        {
2097            let formula: Formula = "P(x) <=> ((! x. Q(x)) <=> R(x))".parse().unwrap();
2098            assert_debug_string("? x`. (! x``. (! x```. (? x````. ((P(x) -> ((Q(x`) -> R(x)) & (R(x) -> Q(x``)))) & (((Q(x```) -> R(x)) & (R(x) -> Q(x````))) -> P(x))))))", formula.pnf());
2099        }
2100        {
2101            let formula: Formula = "P(x) <=> ((? x. Q(x)) <=> R(x))".parse().unwrap();
2102            assert_debug_string("! x`. (? x``. (? x```. (! x````. ((P(x) -> ((Q(x`) -> R(x)) & (R(x) -> Q(x``)))) & (((Q(x```) -> R(x)) & (R(x) -> Q(x````))) -> P(x))))))", formula.pnf());
2103        }
2104        // random formulae
2105        {
2106            let formula: Formula = "!x . (P(x) -> ?y . (P(y) & Q(x, y)))".parse().unwrap();
2107            assert_debug_string("! x. (? y. (P(x) -> (P(y) & Q(x, y))))", formula.pnf());
2108        }
2109        {
2110            let formula: Formula = "?x . (P(x) & !y . (P(y) -> Q(x, y)))".parse().unwrap();
2111            assert_debug_string("? x. (! y. (P(x) & (P(y) -> Q(x, y))))", formula.pnf());
2112        }
2113        {
2114            let formula: Formula = "!x. (P(x) -> ~(!y . (P(y) -> Q(x, y))))".parse().unwrap();
2115            assert_debug_string("! x. (? y. (P(x) -> (~(P(y) -> Q(x, y)))))", formula.pnf());
2116        }
2117        {
2118            let formula: Formula = "(P() | ? x. Q(x)) -> !z. R(z)".parse().unwrap();
2119            assert_debug_string("! x. (! z. ((P() | Q(x)) -> R(z)))", formula.pnf());
2120        }
2121        {
2122            let formula: Formula = "!x.?y.(!z.Q(x) & ~?x.R(x)) | (~Q(y) -> !w. R(y))".parse().unwrap();
2123            assert_debug_string("! x. (? y. (! z. (! x`. (! w. ((Q(x) & (~R(x`))) | ((~Q(y)) -> R(y)))))))", formula.pnf());
2124        }
2125        {
2126            let formula: Formula = "!x. (!y. P(x, y) -> ?y. Q(x, y))".parse().unwrap();
2127            assert_debug_string("! x. (? y. (? y`. (P(x, y) -> Q(x, y`))))", formula.pnf());
2128        }
2129    }
2130
2131    #[test]
2132    fn test_snf() {
2133        assert_debug_string("P('sk#0)"
2134                            , exists1(_x(), P().app1(x())).snf());
2135        assert_debug_string("! x. P(x, sk#0(x))"
2136                            , forall1(_x()
2137                                      , exists1(_y(), P().app2(x(), y()))).snf());
2138        assert_debug_string("P(x, sk#0(x))"
2139                            , exists1(_y(), P().app2(x(), y())).snf());
2140        assert_debug_string("! x. P(x, f(g(sk#0(x)), h(sk#0(x))))"
2141                            , forall1(_x()
2142                                      , exists1(_y()
2143                                                , P().app2(x(), f().app2(g().app1(y()), h().app1(y()))))).snf());
2144        assert_debug_string("('sk#0 = 'sk#1) & ('sk#1 = 'sk#2)",
2145                            exists3(_x(), _y(), _z(), x().equals(y()).and(y().equals(z()))).snf());
2146        assert_debug_string("! y. (Q('sk#0, y) | P(sk#1(y), y, sk#2(y)))"
2147                            , exists1(_x()
2148                                      , forall1(_y()
2149                                                , Q().app2(x(), y())
2150                                                    .or(exists2(_x(), _z(), P().app3(x(), y(), z()))))).snf());
2151        assert_debug_string("! x. (! z. P(x, sk#0(x), z))",
2152                            forall1(_x()
2153                                    , exists1(_y()
2154                                              , forall1(_z()
2155                                                        , P().app3(x(), y(), z())))).snf());
2156        assert_debug_string("! x. (R(g(x)) | R(x, sk#0(x)))"
2157                            , forall1(_x(),
2158                                      R().app1(g().app1(x()))
2159                                          .or(exists1(_y(), R().app2(x(), y())))).snf());
2160        assert_debug_string("! y. (! z. (! v. P('sk#0, y, z, sk#1(y, z), v, sk#2(y, z, v))))"
2161                            , exists1(_x()
2162                                      , forall1(_y()
2163                                                , forall1(_z()
2164                                                          , exists1(_u()
2165                                                                    , forall1(_v()
2166                                                                              , exists1(_w()
2167                                                                                        , P().app(vec![x(), y(), z(), u(), v(), w()]))))))).snf());
2168        {
2169            let mut generator = SkolemGenerator::new();
2170            assert_debug_string("P('sk#0)", exists1(_x(), P().app1(x())).snf_with(&mut generator));
2171            assert_debug_string("Q('sk#1)", exists1(_x(), Q().app1(x())).snf_with(&mut generator));
2172        }
2173    }
2174
2175    #[test]
2176    fn test_nnf() {
2177        {
2178            let formula: Formula = "true".parse().unwrap();
2179            assert_debug_string("true", formula.nnf());
2180        }
2181        {
2182            let formula: Formula = "false".parse().unwrap();
2183            assert_debug_string("false", formula.nnf());
2184        }
2185        {
2186            let formula: Formula = "P(x)".parse().unwrap();
2187            assert_debug_string("P(x)", formula.nnf());
2188        }
2189        {
2190            let formula: Formula = "x = y".parse().unwrap();
2191            assert_debug_string("x = y", formula.nnf());
2192        }
2193        {
2194            let formula: Formula = "~P(x)".parse().unwrap();
2195            assert_debug_string("~P(x)", formula.nnf());
2196        }
2197        {
2198            let formula: Formula = "P(x) & Q(y)".parse().unwrap();
2199            assert_debug_string("P(x) & Q(y)", formula.nnf());
2200        }
2201        {
2202            let formula: Formula = "P(x) | Q(y)".parse().unwrap();
2203            assert_debug_string("P(x) | Q(y)", formula.nnf());
2204        }
2205        {
2206            let formula: Formula = "P(x) -> Q(y)".parse().unwrap();
2207            assert_debug_string("(~P(x)) | Q(y)", formula.nnf());
2208        }
2209        {
2210            let formula: Formula = "P(x) <=> Q(y)".parse().unwrap();
2211            assert_debug_string("((~P(x)) | Q(y)) & (P(x) | (~Q(y)))", formula.nnf());
2212        }
2213        {
2214            let formula: Formula = "?x. P(x)".parse().unwrap();
2215            assert_debug_string("? x. P(x)", formula.nnf());
2216        }
2217        {
2218            let formula: Formula = "!x. P(x)".parse().unwrap();
2219            assert_debug_string("! x. P(x)", formula.nnf());
2220        }
2221        // sanity checking
2222        {
2223            let formula: Formula = "~true".parse().unwrap();
2224            assert_debug_string("false", formula.nnf());
2225        }
2226        {
2227            let formula: Formula = "~false".parse().unwrap();
2228            assert_debug_string("true", formula.nnf());
2229        }
2230        {
2231            let formula: Formula = "~~P(x)".parse().unwrap();
2232            assert_debug_string("P(x)", formula.nnf());
2233        }
2234        {
2235            let formula: Formula = "~~x = y".parse().unwrap();
2236            assert_debug_string("x = y", formula.nnf());
2237        }
2238        {
2239            let formula: Formula = "~(P(x) & Q(y))".parse().unwrap();
2240            assert_debug_string("(~P(x)) | (~Q(y))", formula.nnf());
2241        }
2242        {
2243            let formula: Formula = "~(P(x) | Q(y))".parse().unwrap();
2244            assert_debug_string("(~P(x)) & (~Q(y))", formula.nnf());
2245        }
2246        {
2247            let formula: Formula = "~(P(x) -> Q(y))".parse().unwrap();
2248            assert_debug_string("P(x) & (~Q(y))", formula.nnf());
2249        }
2250        {
2251            let formula: Formula = "~(P(x) <=> Q(y))".parse().unwrap();
2252            assert_debug_string("(P(x) & (~Q(y))) | ((~P(x)) & Q(y))", formula.nnf());
2253        }
2254        {
2255            let formula: Formula = "(P(x) | Q(y)) -> R(z)".parse().unwrap();
2256            assert_debug_string("((~P(x)) & (~Q(y))) | R(z)", formula.nnf());
2257        }
2258        {
2259            let formula: Formula = "(P(x) | Q(y)) <=> R(z)".parse().unwrap();
2260            assert_debug_string("(((~P(x)) & (~Q(y))) | R(z)) & ((P(x) | Q(y)) | (~R(z)))", formula.nnf());
2261        }
2262        {
2263            let formula: Formula = "~?x. P(x)".parse().unwrap();
2264            assert_debug_string("! x. (~P(x))", formula.nnf());
2265        }
2266        {
2267            let formula: Formula = "~!x. P(x)".parse().unwrap();
2268            assert_debug_string("? x. (~P(x))", formula.nnf());
2269        }
2270        // recursive application
2271        {
2272            let formula: Formula = "~~P(x) & ~~Q(y)".parse().unwrap();
2273            assert_debug_string("P(x) & Q(y)", formula.nnf());
2274        }
2275        {
2276            let formula: Formula = "~~P(x) | ~~Q(y)".parse().unwrap();
2277            assert_debug_string("P(x) | Q(y)", formula.nnf());
2278        }
2279        {
2280            let formula: Formula = "~~P(x) -> ~~Q(y)".parse().unwrap();
2281            assert_debug_string("(~P(x)) | Q(y)", formula.nnf());
2282        }
2283        {
2284            let formula: Formula = "~~P(x) <=> ~~Q(y)".parse().unwrap();
2285            assert_debug_string("((~P(x)) | Q(y)) & (P(x) | (~Q(y)))", formula.nnf());
2286        }
2287        {
2288            let formula: Formula = "?x. ~~P(x)".parse().unwrap();
2289            assert_debug_string("? x. P(x)", formula.nnf());
2290        }
2291        {
2292            let formula: Formula = "!x. ~~P(x)".parse().unwrap();
2293            assert_debug_string("! x. P(x)", formula.nnf());
2294        }
2295        {
2296            let formula: Formula = "~~~P(x)".parse().unwrap();
2297            assert_debug_string("~P(x)", formula.nnf());
2298        }
2299        {
2300            let formula: Formula = "~(~P(x) & ~Q(y))".parse().unwrap();
2301            assert_debug_string("P(x) | Q(y)", formula.nnf());
2302        }
2303        {
2304            let formula: Formula = "~(~P(x) | ~Q(y))".parse().unwrap();
2305            assert_debug_string("P(x) & Q(y)", formula.nnf());
2306        }
2307        {
2308            let formula: Formula = "~(~P(x) -> ~Q(y))".parse().unwrap();
2309            assert_debug_string("(~P(x)) & Q(y)", formula.nnf());
2310        }
2311        {
2312            let formula: Formula = "~(~(P(x) & Q(x)) & ~(P(y) & Q(y)))".parse().unwrap();
2313            assert_debug_string("(P(x) & Q(x)) | (P(y) & Q(y))", formula.nnf());
2314        }
2315        {
2316            let formula: Formula = "~(~(P(x) & Q(x)) | ~(P(y) & Q(y)))".parse().unwrap();
2317            assert_debug_string("(P(x) & Q(x)) & (P(y) & Q(y))", formula.nnf());
2318        }
2319        {
2320            let formula: Formula = "~(~(P(x) & Q(x)) -> ~(P(y) & Q(y)))".parse().unwrap();
2321            assert_debug_string("((~P(x)) | (~Q(x))) & (P(y) & Q(y))", formula.nnf());
2322        }
2323        {
2324            let formula: Formula = "~(~(P(x) & Q(x)) <=> ~(P(y) & Q(y)))".parse().unwrap();
2325            assert_debug_string("(((~P(x)) | (~Q(x))) & (P(y) & Q(y))) | ((P(x) & Q(x)) & ((~P(y)) | (~Q(y))))",
2326                                formula.nnf());
2327        }
2328        {
2329            let formula: Formula = "~?x. !y. (P(x) -> Q(y))".parse().unwrap();
2330            assert_debug_string("! x. (? y. (P(x) & (~Q(y))))", formula.nnf());
2331        }
2332        {
2333            let formula: Formula = "~((?x. P(x)) & (!y. Q(y)))".parse().unwrap();
2334            assert_debug_string("(! x. (~P(x))) | (? y. (~Q(y)))", formula.nnf());
2335        }
2336    }
2337
2338    #[test]
2339    fn test_cnf() {
2340        {
2341            let formula: Formula = "true".parse().unwrap();
2342            assert_debug_string("true", formula.cnf());
2343        }
2344        {
2345            let formula: Formula = "false".parse().unwrap();
2346            assert_debug_string("false", formula.cnf());
2347        }
2348        {
2349            let formula: Formula = "P(f(), g(f(), f()))".parse().unwrap();
2350            assert_debug_string("P(f(), g(f(), f()))", formula.cnf());
2351        }
2352        {
2353            let formula: Formula = "P(x)".parse().unwrap();
2354            assert_debug_string("P(x)", formula.cnf());
2355        }
2356        {
2357            let formula: Formula = "x=y".parse().unwrap();
2358            assert_debug_string("x = y", formula.cnf());
2359        }
2360        {
2361            let formula: Formula = "P(x) & Q(y)".parse().unwrap();
2362            assert_debug_string("P(x) & Q(y)", formula.cnf());
2363        }
2364        {
2365            let formula: Formula = "P(x) | Q(y)".parse().unwrap();
2366            assert_debug_string("P(x) | Q(y)", formula.cnf());
2367        }
2368        {
2369            let formula: Formula = "P(x) -> Q(y)".parse().unwrap();
2370            assert_debug_string("(~P(x)) | Q(y)", formula.cnf());
2371        }
2372        {
2373            let formula: Formula = "P(x) <=> Q(y)".parse().unwrap();
2374            assert_debug_string("((~P(x)) | Q(y)) & ((~Q(y)) | P(x))", formula.cnf());
2375        }
2376        {
2377            let formula: Formula = "!x. P(x)".parse().unwrap();
2378            assert_debug_string("P(x)", formula.cnf());
2379        }
2380        {
2381            let formula: Formula = "!x. P(f(), g(f(), x))".parse().unwrap();
2382            assert_debug_string("P(f(), g(f(), x))", formula.cnf());
2383        }
2384        // quantifier-free formulae
2385        {
2386            let formula: Formula = "~((P(x1) | P(x2)) and Q(y))".parse().unwrap();
2387            assert_debug_string("((~P(x1)) | (~Q(y))) & ((~P(x2)) | (~Q(y)))", formula.cnf());
2388        }
2389        {
2390            let formula: Formula = "P(x) | ~(Q(x) -> Q(y))".parse().unwrap();
2391            assert_debug_string("(P(x) | Q(x)) & (P(x) | (~Q(y)))", formula.cnf());
2392        }
2393        {
2394            let formula: Formula = "(P(x) | Q(y)) -> R(z)".parse().unwrap();
2395            assert_debug_string("((~P(x)) | R(z)) & ((~Q(y)) | R(z))", formula.cnf());
2396        }
2397        {
2398            let formula: Formula = "P(x) | ~(Q(x) <=> Q(y))".parse().unwrap();
2399            assert_debug_string("((P(x) | (Q(x) | Q(y))) & (P(x) | (Q(x) | (~Q(x))))) & ((P(x) | ((~Q(y)) | Q(y))) & (P(x) | ((~Q(y)) | (~Q(x)))))",
2400                                formula.cnf());
2401        }
2402        {
2403            let formula: Formula = "(P(x) | Q(y)) <=> R(z)".parse().unwrap();
2404            assert_debug_string("(((~P(x)) | R(z)) & ((~Q(y)) | R(z))) & ((~R(z)) | (P(x) | Q(y)))",
2405                                formula.cnf());
2406        }
2407        {
2408            let formula: Formula = "P(x) | (Q(x) | (R(y) & R(z)))".parse().unwrap();
2409            assert_debug_string("(P(x) | (Q(x) | R(y))) & (P(x) | (Q(x) | R(z)))",
2410                                formula.cnf());
2411        }
2412        {
2413            let formula: Formula = "(P(x1) & P(x2)) | (Q(x1) & Q(x2))".parse().unwrap();
2414            assert_debug_string("((P(x1) | Q(x1)) & (P(x1) | Q(x2))) & ((P(x2) | Q(x1)) & (P(x2) | Q(x2)))",
2415                                formula.cnf());
2416        }
2417        //random formulae
2418        {
2419            let formula: Formula = "?x. P(x)".parse().unwrap();
2420            assert_debug_string("P('sk#0)", formula.cnf());
2421        }
2422        {
2423            let formula: Formula = "?x. (P(x) & Q(f(), x))".parse().unwrap();
2424            assert_debug_string("P('sk#0) & Q(f(), 'sk#0)", formula.cnf());
2425        }
2426        {
2427            let formula: Formula = "!x. ((? y. P(y) & Q(x, y))  -> R(x))".parse().unwrap();
2428            assert_debug_string("((~P(y)) | (~Q(x, y))) | R(x)", formula.cnf());
2429        }
2430        {
2431            let formula: Formula = "!x. (P(x) -> !y. (Q(y) -> ~R(x, y)))".parse().unwrap();
2432            assert_debug_string("(~P(x)) | ((~Q(y)) | (~R(x, y)))", formula.cnf());
2433        }
2434        {
2435            let formula: Formula = "!y. (!x. (P(y, x) | Q(x)) -> Q(y))".parse().unwrap();
2436            assert_debug_string("((~P(y, sk#0(y))) | Q(y)) & ((~Q(sk#0(y))) | Q(y))", formula.cnf());
2437        }
2438        {
2439            let formula: Formula = "?x. ?y. P(x, y)".parse().unwrap();
2440            assert_debug_string("P('sk#0, 'sk#1)", formula.cnf());
2441        }
2442        {
2443            let formula: Formula = "?x, y. P(x, y)".parse().unwrap();
2444            assert_debug_string("P('sk#0, 'sk#1)", formula.cnf());
2445        }
2446        {
2447            let formula: Formula = "!x. ?y. P(x, y)".parse().unwrap();
2448            assert_debug_string("P(x, sk#0(x))", formula.cnf());
2449        }
2450        {
2451            let formula: Formula = "R(z) -> ?u. (!x, y. (P(u, x) & ~? u, x, w. (Q(u, x, y) | (w = f(u)))))".parse().unwrap();
2452            assert_debug_string("((~R(z)) | P(sk#0(z), x)) & (((~R(z)) | (~Q(u`, x`, y))) & ((~R(z)) | (~(w = f(u`)))))",
2453                                formula.cnf());
2454        }
2455        {
2456            let formula: Formula = "!x. (!y. (P(y) -> Q(x, y)) -> ?y. Q(y, x))".parse().unwrap();
2457            assert_debug_string("(P(sk#0(x)) | Q(sk#1(x), x)) & ((~Q(x, sk#0(x))) | Q(sk#1(x), x))",
2458                                formula.cnf());
2459        }
2460        {
2461            let formula: Formula = "?x. (!y, z. (P(x) & ((Q(x, y) & ~(y = z)) -> ~Q(x, z))))".parse().unwrap();
2462            assert_debug_string("P('sk#0) & (((~Q('sk#0, y)) | (y = z)) | (~Q('sk#0, z)))",
2463                                formula.cnf());
2464        }
2465        {
2466            let formula: Formula = "!x. (P(x) -> (!y. (P(y) -> P(f(x, y))) & ~!y. (Q(x, y) -> P(y))))".parse().unwrap();
2467            assert_debug_string("((~P(x)) | ((~P(y)) | P(f(x, y)))) & (((~P(x)) | Q(x, sk#0(x, y))) & ((~P(x)) | (~P(sk#0(x, y)))))",
2468                                formula.cnf());
2469        }
2470    }
2471
2472    #[test]
2473    fn test_dnf() {
2474        {
2475            let formula: Formula = "true".parse().unwrap();
2476            assert_debug_string("true", formula.dnf());
2477        }
2478        {
2479            let formula: Formula = "false".parse().unwrap();
2480            assert_debug_string("false", formula.dnf());
2481        }
2482        {
2483            let formula: Formula = "P(f(), g(f(), f()))".parse().unwrap();
2484            assert_debug_string("P(f(), g(f(), f()))", formula.dnf());
2485        }
2486        {
2487            let formula: Formula = "P(x)".parse().unwrap();
2488            assert_debug_string("P(x)", formula.dnf());
2489        }
2490        {
2491            let formula: Formula = "x=y".parse().unwrap();
2492            assert_debug_string("x = y", formula.dnf());
2493        }
2494        {
2495            let formula: Formula = "P(x) & Q(y)".parse().unwrap();
2496            assert_debug_string("P(x) & Q(y)", formula.dnf());
2497        }
2498        {
2499            let formula: Formula = "P(x) | Q(y)".parse().unwrap();
2500            assert_debug_string("P(x) | Q(y)", formula.dnf());
2501        }
2502        {
2503            let formula: Formula = "P(x) -> Q(y)".parse().unwrap();
2504            assert_debug_string("(~P(x)) | Q(y)", formula.dnf());
2505        }
2506        {
2507            let formula: Formula = "P(x) <=> Q(y)".parse().unwrap();
2508            assert_debug_string("(((~P(x)) & (~Q(y))) | ((~P(x)) & P(x))) | ((Q(y) & (~Q(y))) | (Q(y) & P(x)))",
2509                                formula.dnf());
2510        }
2511        {
2512            let formula: Formula = "!x. P(x)".parse().unwrap();
2513            assert_debug_string("P(x)", formula.dnf());
2514        }
2515        {
2516            let formula: Formula = "!x. P(f(), g(f(), x))".parse().unwrap();
2517            assert_debug_string("P(f(), g(f(), x))", formula.dnf());
2518        }
2519        // quantifier-free formulae
2520        {
2521            let formula: Formula = "~((P(x1) | P(x2)) and Q(y))".parse().unwrap();
2522            assert_debug_string("((~P(x1)) & (~P(x2))) | (~Q(y))", formula.dnf());
2523        }
2524        {
2525            let formula: Formula = "P(x) | ~(Q(x) -> Q(y))".parse().unwrap();
2526            assert_debug_string("P(x) | (Q(x) & (~Q(y)))", formula.dnf());
2527        }
2528        {
2529            let formula: Formula = "(P(x) | Q(y)) -> R(z)".parse().unwrap();
2530            assert_debug_string("((~P(x)) & (~Q(y))) | R(z)", formula.dnf());
2531        }
2532        {
2533            let formula: Formula = "P(x) | ~(Q(x) <=> Q(y))".parse().unwrap();
2534            assert_debug_string("P(x) | ((Q(x) & (~Q(y))) | (Q(y) & (~Q(x))))", formula.dnf());
2535        }
2536        {
2537            let formula: Formula = "(P(x) | Q(y)) <=> R(z)".parse().unwrap();
2538            assert_debug_string("((((~P(x)) & (~Q(y))) & (~R(z))) | ((((~P(x)) & (~Q(y))) & P(x)) | (((~P(x)) & (~Q(y))) & Q(y)))) | ((R(z) & (~R(z))) | ((R(z) & P(x)) | (R(z) & Q(y))))",
2539                                formula.dnf());
2540        }
2541        {
2542            let formula: Formula = "P(x) | (Q(x) | (R(y) & R(z)))".parse().unwrap();
2543            assert_debug_string("P(x) | (Q(x) | (R(y) & R(z)))", formula.dnf());
2544        }
2545        {
2546            let formula: Formula = "(P(x1) & P(x2)) | (Q(x1) & Q(x2))".parse().unwrap();
2547            assert_debug_string("(P(x1) & P(x2)) | (Q(x1) & Q(x2))", formula.dnf());
2548        }
2549
2550        //random formulae
2551        {
2552            let formula: Formula = "?x. P(x)".parse().unwrap();
2553            assert_debug_string("P('sk#0)", formula.dnf());
2554        }
2555        {
2556            let formula: Formula = "?x. (P(x) & Q(f(), x))".parse().unwrap();
2557            assert_debug_string("P('sk#0) & Q(f(), 'sk#0)", formula.dnf());
2558        }
2559        {
2560            let formula: Formula = "!x. ((? y. P(y) & Q(x, y))  -> R(x))".parse().unwrap();
2561            assert_debug_string("((~P(y)) | (~Q(x, y))) | R(x)", formula.dnf());
2562        }
2563        {
2564            let formula: Formula = "!x. (P(x) -> !y. (Q(y) -> ~R(x, y)))".parse().unwrap();
2565            assert_debug_string("(~P(x)) | ((~Q(y)) | (~R(x, y)))", formula.dnf());
2566        }
2567        {
2568            let formula: Formula = "!y. (!x. (P(y, x) | Q(x)) -> Q(y))".parse().unwrap();
2569            assert_debug_string("((~P(y, sk#0(y))) & (~Q(sk#0(y)))) | Q(y)", formula.dnf());
2570        }
2571        {
2572            let formula: Formula = "?x. ?y. P(x, y)".parse().unwrap();
2573            assert_debug_string("P('sk#0, 'sk#1)", formula.dnf());
2574        }
2575        {
2576            let formula: Formula = "?x, y. P(x, y)".parse().unwrap();
2577            assert_debug_string("P('sk#0, 'sk#1)", formula.dnf());
2578        }
2579        {
2580            let formula: Formula = "!x. ?y. P(x, y)".parse().unwrap();
2581            assert_debug_string("P(x, sk#0(x))", formula.dnf());
2582        }
2583        {
2584            let formula: Formula = "R(z) -> ?u. (!x, y. (P(u, x) & ~? u, x, w. (Q(u, x, y) | (w = f(u)))))".parse().unwrap();
2585            assert_debug_string("(~R(z)) | (P(sk#0(z), x) & ((~Q(u`, x`, y)) & (~(w = f(u`)))))",
2586                                formula.dnf());
2587        }
2588        {
2589            let formula: Formula = "!x. (!y. (P(y) -> Q(x, y)) -> ?y. Q(y, x))".parse().unwrap();
2590            assert_debug_string("(P(sk#0(x)) & (~Q(x, sk#0(x)))) | Q(sk#1(x), x)",
2591                                formula.dnf());
2592        }
2593        {
2594            let formula: Formula = "?x. (!y, z. (P(x) & ((Q(x, y) & ~(y = z)) -> ~Q(x, z))))".parse().unwrap();
2595            assert_debug_string("((P('sk#0) & (~Q('sk#0, y))) | (P('sk#0) & (y = z))) | (P('sk#0) & (~Q('sk#0, z)))",
2596                                formula.dnf());
2597        }
2598        {
2599            let formula: Formula = "!x. (P(x) -> (!y. (P(y) -> P(f(x, y))) & ~!y. (Q(x, y) -> P(y))))".parse().unwrap();
2600            assert_debug_string("(~P(x)) | (((~P(y)) & (Q(x, sk#0(x, y)) & (~P(sk#0(x, y))))) | (P(f(x, y)) & (Q(x, sk#0(x, y)) & (~P(sk#0(x, y))))))",
2601                                formula.dnf());
2602        }
2603    }
2604
2605    #[test]
2606    fn test_simplify() {
2607        {
2608            let formula: Formula = "~true".parse().unwrap();
2609            assert_debug_string("false", formula.simplify());
2610        }
2611        {
2612            let formula: Formula = "~false".parse().unwrap();
2613            assert_debug_string("true", formula.simplify());
2614        }
2615        {
2616            let formula: Formula = "~P(x)".parse().unwrap();
2617            assert_debug_string("~P(x)", formula.simplify());
2618        }
2619        {
2620            let formula: Formula = "true & true".parse().unwrap();
2621            assert_debug_string("true", formula.simplify());
2622        }
2623        {
2624            let formula: Formula = "false & false".parse().unwrap();
2625            assert_debug_string("false", formula.simplify());
2626        }
2627        {
2628            let formula: Formula = "false & true".parse().unwrap();
2629            assert_debug_string("false", formula.simplify());
2630        }
2631        {
2632            let formula: Formula = "true & false".parse().unwrap();
2633            assert_debug_string("false", formula.simplify());
2634        }
2635        {
2636            let formula: Formula = "P(x) & true".parse().unwrap();
2637            assert_debug_string("P(x)", formula.simplify());
2638        }
2639        {
2640            let formula: Formula = "false & P(x)".parse().unwrap();
2641            assert_debug_string("false", formula.simplify());
2642        }
2643        {
2644            let formula: Formula = "P(x) & false".parse().unwrap();
2645            assert_debug_string("false", formula.simplify());
2646        }
2647        {
2648            let formula: Formula = "true & P(x)".parse().unwrap();
2649            assert_debug_string("P(x)", formula.simplify());
2650        }
2651        {
2652            let formula: Formula = "P(x) & Q(x)".parse().unwrap();
2653            assert_debug_string("P(x) & Q(x)", formula.simplify());
2654        }
2655        {
2656            let formula: Formula = "true | true".parse().unwrap();
2657            assert_debug_string("true", formula.simplify());
2658        }
2659        {
2660            let formula: Formula = "false | false".parse().unwrap();
2661            assert_debug_string("false", formula.simplify());
2662        }
2663        {
2664            let formula: Formula = "false | true".parse().unwrap();
2665            assert_debug_string("true", formula.simplify());
2666        }
2667        {
2668            let formula: Formula = "true | false".parse().unwrap();
2669            assert_debug_string("true", formula.simplify());
2670        }
2671        {
2672            let formula: Formula = "P(x) | true".parse().unwrap();
2673            assert_debug_string("true", formula.simplify());
2674        }
2675        {
2676            let formula: Formula = "false | P(x)".parse().unwrap();
2677            assert_debug_string("P(x)", formula.simplify());
2678        }
2679        {
2680            let formula: Formula = "P(x) | false".parse().unwrap();
2681            assert_debug_string("P(x)", formula.simplify());
2682        }
2683        {
2684            let formula: Formula = "true | P(x)".parse().unwrap();
2685            assert_debug_string("true", formula.simplify());
2686        }
2687        {
2688            let formula: Formula = "P(x) | Q(x)".parse().unwrap();
2689            assert_debug_string("P(x) | Q(x)", formula.simplify());
2690        }
2691        {
2692            let formula: Formula = "true -> true".parse().unwrap();
2693            assert_debug_string("true", formula.simplify());
2694        }
2695        {
2696            let formula: Formula = "false -> false".parse().unwrap();
2697            assert_debug_string("true", formula.simplify());
2698        }
2699        {
2700            let formula: Formula = "false -> true".parse().unwrap();
2701            assert_debug_string("true", formula.simplify());
2702        }
2703        {
2704            let formula: Formula = "true -> false".parse().unwrap();
2705            assert_debug_string("false", formula.simplify());
2706        }
2707        {
2708            let formula: Formula = "P(x) -> true".parse().unwrap();
2709            assert_debug_string("true", formula.simplify());
2710        }
2711        {
2712            let formula: Formula = "false -> P(x)".parse().unwrap();
2713            assert_debug_string("true", formula.simplify());
2714        }
2715        {
2716            let formula: Formula = "P(x) -> false".parse().unwrap();
2717            assert_debug_string("~P(x)", formula.simplify());
2718        }
2719        {
2720            let formula: Formula = "true -> P(x)".parse().unwrap();
2721            assert_debug_string("P(x)", formula.simplify());
2722        }
2723        {
2724            let formula: Formula = "P(x) -> Q(x)".parse().unwrap();
2725            assert_debug_string("P(x) -> Q(x)", formula.simplify());
2726        }
2727        {
2728            let formula: Formula = "true <=> true".parse().unwrap();
2729            assert_debug_string("true", formula.simplify());
2730        }
2731        {
2732            let formula: Formula = "false <=> false".parse().unwrap();
2733            assert_debug_string("true", formula.simplify());
2734        }
2735        {
2736            let formula: Formula = "false <=> true".parse().unwrap();
2737            assert_debug_string("false", formula.simplify());
2738        }
2739        {
2740            let formula: Formula = "true <=> false".parse().unwrap();
2741            assert_debug_string("false", formula.simplify());
2742        }
2743        {
2744            let formula: Formula = "P(x) <=> true".parse().unwrap();
2745            assert_debug_string("P(x)", formula.simplify());
2746        }
2747        {
2748            let formula: Formula = "false <=> P(x)".parse().unwrap();
2749            assert_debug_string("~P(x)", formula.simplify());
2750        }
2751        {
2752            let formula: Formula = "P(x) <=> false".parse().unwrap();
2753            assert_debug_string("~P(x)", formula.simplify());
2754        }
2755        {
2756            let formula: Formula = "true <=> P(x)".parse().unwrap();
2757            assert_debug_string("P(x)", formula.simplify());
2758        }
2759        {
2760            let formula: Formula = "P(x) <=> Q(x)".parse().unwrap();
2761            assert_debug_string("P(x) <=> Q(x)", formula.simplify());
2762        }
2763        {
2764            let formula: Formula = "?x, y. P(y, z)".parse().unwrap();
2765            assert_debug_string("? y. P(y, z)", formula.simplify());
2766        }
2767        {
2768            let formula: Formula = "?x. P(x)".parse().unwrap();
2769            assert_debug_string("? x. P(x)", formula.simplify());
2770        }
2771        {
2772            let formula: Formula = "?x. P(y)".parse().unwrap();
2773            assert_debug_string("P(y)", formula.simplify());
2774        }
2775        {
2776            let formula: Formula = "!x, y. P(y, z)".parse().unwrap();
2777            assert_debug_string("! y. P(y, z)", formula.simplify());
2778        }
2779        {
2780            let formula: Formula = "!x. P(x)".parse().unwrap();
2781            assert_debug_string("! x. P(x)", formula.simplify());
2782        }
2783        {
2784            let formula: Formula = "!x. P(y)".parse().unwrap();
2785            assert_debug_string("P(y)", formula.simplify());
2786        }
2787        // random formulae
2788        {
2789            let formula: Formula = "~~P(x)".parse().unwrap();
2790            assert_debug_string("P(x)", formula.simplify());
2791        }
2792        {
2793            let formula: Formula = "~~~P(x)".parse().unwrap();
2794            assert_debug_string("~P(x)", formula.simplify());
2795        }
2796        {
2797            let formula: Formula = "~(true -> false)".parse().unwrap();
2798            assert_debug_string("true", formula.simplify());
2799        }
2800        {
2801            let formula: Formula = "false | (P(x) & true)".parse().unwrap();
2802            assert_debug_string("P(x)", formula.simplify());
2803        }
2804        {
2805            let formula: Formula = "?x. P(x) | true".parse().unwrap();
2806            assert_debug_string("true", formula.simplify());
2807        }
2808        {
2809            let formula: Formula = "?y. (P(x) -> false) & (false -> Q(x))".parse().unwrap();
2810            assert_debug_string("~P(x)", formula.simplify());
2811        }
2812        {
2813            let formula: Formula = "!x. ?y. P(x, y) | true".parse().unwrap();
2814            assert_debug_string("true", formula.simplify());
2815        }
2816        {
2817            let formula: Formula = "(((x = y -> false) -> false) -> false) -> false".parse().unwrap();
2818            assert_debug_string("x = y", formula.simplify());
2819        }
2820        {
2821            let formula: Formula = "!x, y, z. ?z. P(x) | w = x".parse().unwrap();
2822            assert_debug_string("! x. (P(x) | (w = x))", formula.simplify());
2823        }
2824        {
2825            let formula: Formula = "(P(x) | false) | (P(x) | true)".parse().unwrap();
2826            assert_debug_string("true", formula.simplify());
2827        }
2828        {
2829            let formula: Formula = "(P(x) & false) & (P(x) & true)".parse().unwrap();
2830            assert_debug_string("false", formula.simplify());
2831        }
2832    }
2833
2834    #[test]
2835    fn test_gnf() {
2836        {
2837            let formula: Formula = "true".parse().unwrap();
2838            assert_debug_strings("true -> true", formula.gnf());
2839        }
2840        {
2841            let formula: Formula = "false".parse().unwrap();
2842            assert_debug_strings("true -> false", formula.gnf());
2843        }
2844        {
2845            let formula: Formula = "P(x)".parse().unwrap();
2846            assert_debug_strings("true -> P(x)", formula.gnf());
2847        }
2848        {
2849            let formula: Formula = "x = y".parse().unwrap();
2850            assert_debug_strings("true -> (x = y)", formula.gnf());
2851        }
2852        {
2853            let formula: Formula = "~P(x)".parse().unwrap();
2854            assert_debug_strings("P(x) -> false", formula.gnf());
2855        }
2856        {
2857            let formula: Formula = "P(x) -> Q(x)".parse().unwrap();
2858            assert_debug_strings("P(x) -> Q(x)", formula.gnf());
2859        }
2860        {
2861            let formula: Formula = "P(x) & Q(x)".parse().unwrap();
2862            assert_debug_strings("true -> P(x)\ntrue -> Q(x)", formula.gnf());
2863        }
2864        {
2865            let formula: Formula = "P(x) | Q(x)".parse().unwrap();
2866            assert_debug_strings("true -> (P(x) | Q(x))", formula.gnf());
2867        }
2868        {
2869            let formula: Formula = "! x. P(x)".parse().unwrap();
2870            assert_debug_strings("true -> P(x)", formula.gnf());
2871        }
2872        {
2873            let formula: Formula = "? x. P(x)".parse().unwrap();
2874            assert_debug_strings("true -> P('sk#0)", formula.gnf());
2875        }
2876        {
2877            let formula: Formula = "P(x) & Q(x) -> P(y) | Q(y)".parse().unwrap();
2878            assert_debug_strings("(P(x) & Q(x)) -> (P(y) | Q(y))", formula.gnf());
2879        }
2880        {
2881            let formula: Formula = "P(x) | Q(x) -> P(y) & Q(y)".parse().unwrap();
2882            assert_debug_strings("P(x) -> P(y)\n\
2883        P(x) -> Q(y)\n\
2884        Q(x) -> P(y)\n\
2885        Q(x) -> Q(y)", formula.gnf());
2886        }
2887        {
2888            let formula: Formula = "P(x) | Q(x) <=> P(y) & Q(y)".parse().unwrap();
2889            assert_debug_strings("P(x) -> P(y)\n\
2890        P(x) -> Q(y)\n\
2891        Q(x) -> P(y)\n\
2892        Q(x) -> Q(y)\n\
2893        (P(y) & Q(y)) -> (P(x) | Q(x))", formula.gnf());
2894        }
2895        {
2896            let formula: Formula = "!x. (P(x) -> ?y. Q(x,y))".parse().unwrap();
2897            assert_debug_strings("P(x) -> Q(x, sk#0(x))", formula.gnf());
2898        }
2899        {
2900            let formula: Formula = "!x. (P(x) -> (?y. (Q(y) & R(x, y)) | ?y. (P(y) & S(x, y)))))".parse().unwrap();
2901            assert_debug_strings("P(x) -> (Q(sk#0(x)) | P(sk#1(x)))\n\
2902        P(x) -> (Q(sk#0(x)) | S(x, sk#1(x)))\n\
2903        P(x) -> (R(x, sk#0(x)) | P(sk#1(x)))\n\
2904        P(x) -> (R(x, sk#0(x)) | S(x, sk#1(x)))", formula.gnf());
2905        }
2906        {
2907            let formula: Formula = "!x, y. ((P(x) & Q(y)) -> (R(x, y) -> S(x, y)))".parse().unwrap();
2908            assert_debug_strings("((P(x) & Q(y)) & R(x, y)) -> S(x, y)", formula.gnf());
2909        }
2910        {
2911            let formula: Formula = "!x, y. ((P(x) & Q(y)) <=> (R(x, y) <=> S(x, y)))".parse().unwrap();
2912            assert_debug_strings("((P(x) & Q(y)) & R(x, y)) -> S(x, y)\n\
2913        ((P(x) & Q(y)) & S(x, y)) -> R(x, y)\n\
2914        true -> ((R(x, y) | S(x, y)) | P(x))\n\
2915        true -> ((R(x, y) | S(x, y)) | Q(y))\n\
2916        R(x, y) -> (R(x, y) | P(x))\n\
2917        R(x, y) -> (R(x, y) | Q(y))\n\
2918        S(x, y) -> (S(x, y) | P(x))\n\
2919        S(x, y) -> (S(x, y) | Q(y))\n\
2920        (S(x, y) & R(x, y)) -> P(x)\n\
2921        (S(x, y) & R(x, y)) -> Q(y)", formula.gnf());
2922        }
2923        {
2924            let formula: Formula = "? x. P(x) -> Q(x)".parse().unwrap();
2925            assert_debug_strings("P(x`) -> Q(x)", formula.gnf());
2926        }
2927        {
2928            let formula: Formula = "? x. (P(x) -> Q(x))".parse().unwrap();
2929            assert_debug_strings("P('sk#0) -> Q('sk#0)", formula.gnf());
2930        }
2931        {
2932            let formula: Formula = "false -> P(x)".parse().unwrap();
2933            assert_debug_strings("true -> true", formula.gnf());
2934        }
2935    }
2936
2937    #[test]
2938    fn test_gnf_theory() {
2939        // mostly testing if compression of heads works properly:
2940        {
2941            let theory: Theory = "P('a); P('b);".parse().unwrap();
2942            assert_debug_strings("true -> (P('a) & P('b))", theory.gnf().formulae);
2943        }
2944        {
2945            let theory: Theory = "P('a); P(x);".parse().unwrap();
2946            assert_debug_strings("true -> P(x)\ntrue -> P('a)", theory.gnf().formulae);
2947        }
2948        {
2949            let theory: Theory = "P('a); P(x); P('b);".parse().unwrap();
2950            assert_debug_strings("true -> P(x)\ntrue -> (P(\'a) & P(\'b))", theory.gnf().formulae);
2951        }
2952        {
2953            let theory: Theory = "(T() and V()) or (U() and V());".parse().unwrap();
2954            assert_debug_strings("true -> ((T() & V()) | (U() & V()))", theory.gnf().formulae);
2955        }
2956    }
2957}