1use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6use std::collections::{HashMap, HashSet, VecDeque};
7
8use super::types::{
9 DependencyPairGraph, EGraph, KnuthBendixData, NarrowingSystem, PolynomialInterpretation,
10 ReductionStrategy, RewritingLogicTheory, Rule, Srs, Strategy, StringRewritingSystem,
11 Substitution, Term, TreeAutomaton, Trs,
12};
13
14pub fn app(f: Expr, a: Expr) -> Expr {
15 Expr::App(Box::new(f), Box::new(a))
16}
17pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
18 app(app(f, a), b)
19}
20pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
21 app(app2(f, a, b), c)
22}
23pub fn cst(s: &str) -> Expr {
24 Expr::Const(Name::str(s), vec![])
25}
26pub fn prop() -> Expr {
27 Expr::Sort(Level::zero())
28}
29pub fn type0() -> Expr {
30 Expr::Sort(Level::succ(Level::zero()))
31}
32pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
33 Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
34}
35pub fn arrow(a: Expr, b: Expr) -> Expr {
36 pi(BinderInfo::Default, "_", a, b)
37}
38pub fn bvar(n: u32) -> Expr {
39 Expr::BVar(n)
40}
41pub fn nat_ty() -> Expr {
42 cst("Nat")
43}
44pub fn bool_ty() -> Expr {
45 cst("Bool")
46}
47pub fn string_ty() -> Expr {
48 cst("String")
49}
50pub fn list_nat() -> Expr {
51 app(cst("List"), nat_ty())
52}
53pub fn option_ty(t: Expr) -> Expr {
54 app(cst("Option"), t)
55}
56pub fn term_ty() -> Expr {
58 type0()
59}
60pub fn signature_ty() -> Expr {
62 type0()
63}
64pub fn variable_ty() -> Expr {
66 type0()
67}
68pub fn substitution_ty() -> Expr {
70 arrow(variable_ty(), term_ty())
71}
72pub fn rewrite_rule_ty() -> Expr {
74 type0()
75}
76pub fn trs_ty() -> Expr {
78 type0()
79}
80pub fn reduction_ty() -> Expr {
82 arrow(term_ty(), arrow(term_ty(), prop()))
83}
84pub fn refl_trans_closure_ty() -> Expr {
86 arrow(
87 arrow(term_ty(), arrow(term_ty(), prop())),
88 arrow(term_ty(), arrow(term_ty(), prop())),
89 )
90}
91pub fn confluence_ty() -> Expr {
93 arrow(trs_ty(), prop())
94}
95pub fn local_confluence_ty() -> Expr {
97 arrow(trs_ty(), prop())
98}
99pub fn strong_normalization_ty() -> Expr {
101 arrow(trs_ty(), prop())
102}
103pub fn weak_normalization_ty() -> Expr {
105 arrow(trs_ty(), prop())
106}
107pub fn normal_form_ty() -> Expr {
109 arrow(trs_ty(), arrow(term_ty(), prop()))
110}
111pub fn critical_pair_ty() -> Expr {
113 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop())))
114}
115pub fn orthogonal_ty() -> Expr {
117 arrow(trs_ty(), prop())
118}
119pub fn left_linear_ty() -> Expr {
121 arrow(trs_ty(), prop())
122}
123pub fn ground_trs_ty() -> Expr {
125 arrow(trs_ty(), prop())
126}
127pub fn position_ty() -> Expr {
129 list_nat()
130}
131pub fn subterm_ty() -> Expr {
133 arrow(term_ty(), arrow(position_ty(), term_ty()))
134}
135pub fn replace_ty() -> Expr {
137 arrow(term_ty(), arrow(position_ty(), arrow(term_ty(), term_ty())))
138}
139pub fn unifier_ty() -> Expr {
141 arrow(
142 term_ty(),
143 arrow(term_ty(), arrow(substitution_ty(), prop())),
144 )
145}
146pub fn mgu_ty() -> Expr {
148 arrow(
149 term_ty(),
150 arrow(term_ty(), arrow(substitution_ty(), prop())),
151 )
152}
153pub fn kb_completion_ty() -> Expr {
155 arrow(trs_ty(), arrow(trs_ty(), prop()))
156}
157pub fn word_problem_ty() -> Expr {
159 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), bool_ty())))
160}
161pub fn srs_ty() -> Expr {
163 type0()
164}
165pub fn reduction_strategy_ty() -> Expr {
167 type0()
168}
169pub fn equational_unification_ty() -> Expr {
171 arrow(term_ty(), arrow(term_ty(), arrow(term_ty(), prop())))
172}
173pub fn newmans_lemma_ty() -> Expr {
176 pi(
177 BinderInfo::Default,
178 "R",
179 trs_ty(),
180 arrow(
181 app(cst("LocalConfluence"), bvar(0)),
182 arrow(
183 app(cst("StrongNormalization"), bvar(1)),
184 app(cst("Confluence"), bvar(2)),
185 ),
186 ),
187 )
188}
189pub fn church_rosser_ty() -> Expr {
192 pi(
193 BinderInfo::Default,
194 "R",
195 trs_ty(),
196 app2(
197 cst("Iff"),
198 app(cst("Confluence"), bvar(0)),
199 app(cst("ChurchRosserProp"), bvar(0)),
200 ),
201 )
202}
203pub fn orthogonal_confluent_ty() -> Expr {
206 pi(
207 BinderInfo::Default,
208 "R",
209 trs_ty(),
210 arrow(
211 app(cst("Orthogonal"), bvar(0)),
212 app(cst("Confluence"), bvar(0)),
213 ),
214 )
215}
216pub fn redei_theorem_ty() -> Expr {
218 prop()
219}
220pub fn ground_confluence_decidable_ty() -> Expr {
222 pi(
223 BinderInfo::Default,
224 "R",
225 trs_ty(),
226 arrow(
227 app(cst("GroundTRS"), bvar(0)),
228 app(cst("Decidable"), app(cst("Confluence"), bvar(1))),
229 ),
230 )
231}
232pub fn unique_normal_forms_ty() -> Expr {
234 pi(
235 BinderInfo::Default,
236 "R",
237 trs_ty(),
238 arrow(
239 app(cst("Confluence"), bvar(0)),
240 pi(
241 BinderInfo::Default,
242 "t",
243 term_ty(),
244 pi(
245 BinderInfo::Default,
246 "u",
247 term_ty(),
248 pi(
249 BinderInfo::Default,
250 "v",
251 term_ty(),
252 arrow(
253 app3(cst("ReducesTo"), bvar(3), bvar(2), bvar(1)),
254 arrow(
255 app3(cst("ReducesTo"), bvar(4), bvar(3), bvar(0)),
256 app2(cst("Eq"), bvar(2), bvar(1)),
257 ),
258 ),
259 ),
260 ),
261 ),
262 ),
263 )
264}
265pub fn kb_completeness_ty() -> Expr {
267 prop()
268}
269pub fn build_term_rewriting_env(env: &mut Environment) -> Result<(), String> {
271 for (name, ty) in [
272 ("TrsTerm", term_ty()),
273 ("TrsSignature", signature_ty()),
274 ("TrsVariable", variable_ty()),
275 ("TrsSubstitution", substitution_ty()),
276 ("TrsRewriteRule", rewrite_rule_ty()),
277 ("TRS", trs_ty()),
278 ("TrsPosition", position_ty()),
279 ("SRS", srs_ty()),
280 ("ReductionStrategy", reduction_strategy_ty()),
281 ] {
282 env.add(Declaration::Axiom {
283 name: Name::str(name),
284 univ_params: vec![],
285 ty,
286 })
287 .ok();
288 }
289 for (name, ty) in [
290 ("Confluence", confluence_ty()),
291 ("LocalConfluence", local_confluence_ty()),
292 ("StrongNormalization", strong_normalization_ty()),
293 ("WeakNormalization", weak_normalization_ty()),
294 ("NormalForm", normal_form_ty()),
295 ("CriticalPair", critical_pair_ty()),
296 ("Orthogonal", orthogonal_ty()),
297 ("LeftLinear", left_linear_ty()),
298 ("GroundTRS", ground_trs_ty()),
299 ("Unifier", unifier_ty()),
300 ("MGU", mgu_ty()),
301 ("KBCompletion", kb_completion_ty()),
302 ("EquationalUnification", equational_unification_ty()),
303 ("ChurchRosserProp", arrow(trs_ty(), prop())),
304 (
305 "ReducesTo",
306 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
307 ),
308 (
309 "EquivalentUnder",
310 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
311 ),
312 ] {
313 env.add(Declaration::Axiom {
314 name: Name::str(name),
315 univ_params: vec![],
316 ty,
317 })
318 .ok();
319 }
320 for (name, ty) in [
321 ("trsSubterm", subterm_ty()),
322 ("trsReplace", replace_ty()),
323 (
324 "trsApplySubst",
325 arrow(substitution_ty(), arrow(term_ty(), term_ty())),
326 ),
327 (
328 "trsUnify",
329 arrow(term_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
330 ),
331 (
332 "trsMGU",
333 arrow(term_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
334 ),
335 (
336 "trsNormalForm",
337 arrow(trs_ty(), arrow(term_ty(), term_ty())),
338 ),
339 (
340 "trsReduceInnermost",
341 arrow(trs_ty(), arrow(term_ty(), term_ty())),
342 ),
343 (
344 "trsReduceOutermost",
345 arrow(trs_ty(), arrow(term_ty(), term_ty())),
346 ),
347 ] {
348 env.add(Declaration::Axiom {
349 name: Name::str(name),
350 univ_params: vec![],
351 ty,
352 })
353 .ok();
354 }
355 for (name, ty) in [
356 ("NewmansLemma", newmans_lemma_ty()),
357 ("ChurchRosserThm", church_rosser_ty()),
358 ("OrthogonalConfluentThm", orthogonal_confluent_ty()),
359 ("RedeiTheorem", redei_theorem_ty()),
360 (
361 "GroundConfluenceDecidable",
362 ground_confluence_decidable_ty(),
363 ),
364 ("UniqueNormalForms", unique_normal_forms_ty()),
365 ("KBCompletenessThm", kb_completeness_ty()),
366 ("TerminationImpliesWN", prop()),
367 ("SNImpliesWN", prop()),
368 ("ConfluenceImpliesLocalConfluence", prop()),
369 ("LeftLinearNoCPConfluent", prop()),
370 ("CriticalPairLemma", prop()),
371 ("CommutativityWordProblem", prop()),
372 ("TotalTerminationCriterion", prop()),
373 ("KBTermination", prop()),
374 ("SubstitutionLemma", prop()),
375 ("PositionInduction", prop()),
376 ("ReplaceLemma", prop()),
377 ("DepthTermination", prop()),
378 ("LexicographicPathOrder", prop()),
379 ("RecursivePathOrder", prop()),
380 ("PolynomialInterpretationThm", prop()),
381 ("EquationalTheoryAxiom", arrow(trs_ty(), prop())),
382 (
383 "RewritingModuloE",
384 arrow(
385 trs_ty(),
386 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
387 ),
388 ),
389 (
390 "ACRewriting",
391 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
392 ),
393 (
394 "ACUnification",
395 arrow(term_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
396 ),
397 ("BEquationalAxiom", arrow(trs_ty(), prop())),
398 ("HigherOrderTRS", arrow(trs_ty(), prop())),
399 ("CombReductionSystem", arrow(trs_ty(), prop())),
400 ("HRSConfluence", arrow(trs_ty(), prop())),
401 ("LambdaCalculusEncoding", arrow(term_ty(), term_ty())),
402 ("BetaReduction", arrow(term_ty(), option_ty(term_ty()))),
403 (
404 "DependencyPair",
405 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
406 ),
407 ("DependencyGraph", arrow(trs_ty(), type0())),
408 (
409 "DependencyPairMethod",
410 arrow(trs_ty(), arrow(trs_ty(), prop())),
411 ),
412 ("SccsTermination", arrow(trs_ty(), prop())),
413 ("DPChain", arrow(trs_ty(), arrow(term_ty(), prop()))),
414 (
415 "ReductionOrdering",
416 arrow(arrow(term_ty(), arrow(term_ty(), prop())), prop()),
417 ),
418 ("PolynomialOrder", arrow(nat_ty(), arrow(trs_ty(), prop()))),
419 ("RecursivePathOrdering", arrow(trs_ty(), prop())),
420 ("KnuthBendixOrder", arrow(trs_ty(), prop())),
421 ("WeightFunction", arrow(term_ty(), nat_ty())),
422 (
423 "SimplificationOrder",
424 arrow(arrow(term_ty(), arrow(term_ty(), prop())), prop()),
425 ),
426 (
427 "NarrowingStep",
428 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
429 ),
430 (
431 "LazyNarrowing",
432 arrow(trs_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
433 ),
434 (
435 "BasicNarrowing",
436 arrow(trs_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
437 ),
438 ("NarrowingCompleteness", arrow(trs_ty(), prop())),
439 (
440 "NarrowingUnification",
441 arrow(term_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
442 ),
443 ("TreeAutomaton", type0()),
444 ("RegularTreeLanguage", arrow(cst("TreeAutomaton"), type0())),
445 (
446 "TreeAutomataIntersection",
447 arrow(
448 cst("TreeAutomaton"),
449 arrow(cst("TreeAutomaton"), cst("TreeAutomaton")),
450 ),
451 ),
452 (
453 "TreeAutomataUnion",
454 arrow(
455 cst("TreeAutomaton"),
456 arrow(cst("TreeAutomaton"), cst("TreeAutomaton")),
457 ),
458 ),
459 (
460 "TreeAutomataComplementation",
461 arrow(cst("TreeAutomaton"), cst("TreeAutomaton")),
462 ),
463 (
464 "TRSPreservesRegularity",
465 arrow(trs_ty(), arrow(cst("TreeAutomaton"), prop())),
466 ),
467 (
468 "TreeLanguageMembership",
469 arrow(term_ty(), arrow(cst("TreeAutomaton"), prop())),
470 ),
471 (
472 "CongruenceClosure",
473 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
474 ),
475 ("GroundCongruenceClosure", arrow(trs_ty(), prop())),
476 (
477 "NelsonOppenCombination",
478 arrow(trs_ty(), arrow(trs_ty(), prop())),
479 ),
480 ("SharingCongruence", arrow(trs_ty(), prop())),
481 ("HuetsCompletion", arrow(trs_ty(), arrow(trs_ty(), prop()))),
482 ("PetersonStickel", arrow(trs_ty(), arrow(trs_ty(), prop()))),
483 (
484 "OrderedCompletion",
485 arrow(trs_ty(), arrow(trs_ty(), prop())),
486 ),
487 ("CompletionTerminates", arrow(trs_ty(), prop())),
488 ("RosensLemma", prop()),
489 (
490 "ModularConfluence",
491 arrow(trs_ty(), arrow(trs_ty(), prop())),
492 ),
493 ("ParallelClosure", arrow(trs_ty(), prop())),
494 (
495 "ConfluentIntersection",
496 arrow(trs_ty(), arrow(trs_ty(), prop())),
497 ),
498 ("RewritingLogicTheory", type0()),
499 (
500 "ConcurrentRewrite",
501 arrow(
502 cst("RewritingLogicTheory"),
503 arrow(term_ty(), arrow(term_ty(), prop())),
504 ),
505 ),
506 (
507 "RewritingLogicSoundness",
508 arrow(cst("RewritingLogicTheory"), prop()),
509 ),
510 (
511 "MaudeSystemAxiom",
512 arrow(cst("RewritingLogicTheory"), prop()),
513 ),
514 ("SufficientCompleteness", arrow(trs_ty(), prop())),
515 (
516 "GroundReducibility",
517 arrow(trs_ty(), arrow(term_ty(), prop())),
518 ),
519 (
520 "InductiveTheorem",
521 arrow(trs_ty(), arrow(term_ty(), prop())),
522 ),
523 ("ConstructorSystem", arrow(trs_ty(), prop())),
524 (
525 "ACMatching",
526 arrow(term_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
527 ),
528 (
529 "ACUMatching",
530 arrow(term_ty(), arrow(term_ty(), option_ty(substitution_ty()))),
531 ),
532 ("FreeAlgebraConstraint", arrow(trs_ty(), prop())),
533 (
534 "MatchingModuloAxiom",
535 arrow(trs_ty(), arrow(term_ty(), arrow(term_ty(), prop()))),
536 ),
537 ] {
538 env.add(Declaration::Axiom {
539 name: Name::str(name),
540 univ_params: vec![],
541 ty,
542 })
543 .ok();
544 }
545 Ok(())
546}
547pub fn unify(s: &Term, t: &Term) -> Option<Substitution> {
551 let mut equations: Vec<(Term, Term)> = vec![(s.clone(), t.clone())];
552 let mut subst = Substitution::new();
553 while let Some((lhs, rhs)) = equations.pop() {
554 let lhs = lhs.apply(&subst);
555 let rhs = rhs.apply(&subst);
556 if lhs == rhs {
557 continue;
558 }
559 match (&lhs, &rhs) {
560 (Term::Var(x), _) => {
561 if rhs.contains(&Term::Var(*x)) {
562 return None;
563 }
564 let bind = Substitution {
565 map: HashMap::from([(*x, rhs.clone())]),
566 };
567 let mut new_map = HashMap::new();
568 for (&v, t) in &subst.map {
569 new_map.insert(v, t.apply(&bind));
570 }
571 new_map.insert(*x, rhs.clone());
572 subst.map = new_map;
573 }
574 (_, Term::Var(y)) => {
575 if lhs.contains(&Term::Var(*y)) {
576 return None;
577 }
578 let bind = Substitution {
579 map: HashMap::from([(*y, lhs.clone())]),
580 };
581 let mut new_map = HashMap::new();
582 for (&v, t) in &subst.map {
583 new_map.insert(v, t.apply(&bind));
584 }
585 new_map.insert(*y, lhs.clone());
586 subst.map = new_map;
587 }
588 (Term::Fun(f, fa), Term::Fun(g, ga)) => {
589 if f != g || fa.len() != ga.len() {
590 return None;
591 }
592 for (a, b) in fa.iter().zip(ga.iter()) {
593 equations.push((a.clone(), b.clone()));
594 }
595 }
596 }
597 }
598 Some(subst)
599}
600pub fn unifiable(s: &Term, t: &Term) -> bool {
602 unify(s, t).is_some()
603}
604pub fn critical_pairs(r1: &Rule, r2: &Rule, offset: u32) -> Vec<(Term, Term)> {
612 let r1 = r1.clone();
613 let r2 = r2.rename(offset);
614 let mut pairs = Vec::new();
615 fn non_var_positions(t: &Term) -> Vec<Vec<usize>> {
616 match t {
617 Term::Var(_) => vec![],
618 Term::Fun(_, args) => {
619 let mut out = vec![vec![]];
620 for (i, a) in args.iter().enumerate() {
621 for mut p in non_var_positions(a) {
622 let mut full = vec![i];
623 full.append(&mut p);
624 out.push(full);
625 }
626 }
627 out
628 }
629 }
630 }
631 for pos in non_var_positions(&r1.lhs) {
632 if let Some(sub) = r1.lhs.subterm_at(&pos) {
633 if let Some(sigma) = unify(sub, &r2.lhs) {
634 let left = r1.lhs.replace_at(&pos, r2.rhs.apply(&sigma)).apply(&sigma);
635 let right = r1.rhs.apply(&sigma);
636 if left != right {
637 pairs.push((left, right));
638 }
639 }
640 }
641 }
642 pairs
643}
644pub fn check_local_confluence(trs: &Trs, limit: usize) -> bool {
649 let n = trs.rules.len();
650 for i in 0..n {
651 for j in 0..n {
652 let pairs = critical_pairs(
653 &trs.rules[i],
654 &trs.rules[j],
655 (i * 1000 + j * 1000 + 2000) as u32,
656 );
657 for (s, t) in pairs {
658 let ns = trs.normalize_innermost(&s, limit);
659 let nt = trs.normalize_innermost(&t, limit);
660 if ns != nt {
661 return false;
662 }
663 }
664 }
665 }
666 true
667}
668pub type TermOrdering = fn(&Term, &Term) -> std::cmp::Ordering;
670pub fn reduce_step(trs: &Trs, term: &Term, strategy: Strategy) -> Option<Term> {
672 match strategy {
673 Strategy::Innermost | Strategy::Lazy => trs.reduce_innermost(term),
674 Strategy::Outermost | Strategy::Parallel => trs.reduce_outermost(term),
675 }
676}
677#[cfg(test)]
678mod tests {
679 use super::*;
680 fn f(args: Vec<Term>) -> Term {
681 Term::Fun("f".into(), args)
682 }
683 fn g(args: Vec<Term>) -> Term {
684 Term::Fun("g".into(), args)
685 }
686 fn a() -> Term {
687 Term::Fun("a".into(), vec![])
688 }
689 fn b() -> Term {
690 Term::Fun("b".into(), vec![])
691 }
692 fn x0() -> Term {
693 Term::Var(0)
694 }
695 fn x1() -> Term {
696 Term::Var(1)
697 }
698 #[test]
700 fn test_build_env() {
701 let mut env = Environment::new();
702 let result = build_term_rewriting_env(&mut env);
703 assert!(result.is_ok());
704 }
705 #[test]
707 fn test_unification_basic() {
708 let s = f(vec![x0(), a()]);
709 let t = f(vec![b(), x1()]);
710 let mgu = unify(&s, &t).expect("should unify");
711 let s2 = s.apply(&mgu);
712 let t2 = t.apply(&mgu);
713 assert_eq!(s2, t2);
714 }
715 #[test]
717 fn test_unification_occurs_check() {
718 let result = unify(&x0(), &f(vec![x0()]));
719 assert!(result.is_none(), "occurs check should prevent self-loop");
720 }
721 #[test]
723 fn test_unification_clash() {
724 let result = unify(&f(vec![a()]), &g(vec![a()]));
725 assert!(result.is_none());
726 }
727 #[test]
729 fn test_innermost_normalization() {
730 let mut trs = Trs::new();
731 trs.add_rule(Rule::new(f(vec![f(vec![x0()])]), f(vec![x0()])));
732 let term = f(vec![f(vec![f(vec![a()])])]);
733 let nf = trs.normalize_innermost(&term, 10);
734 assert_eq!(nf, f(vec![a()]));
735 }
736 #[test]
738 fn test_srs_word_problem() {
739 let mut srs = Srs::new();
740 srs.add_rule("ba", "ab");
741 let nf = srs.normalize("bba", 10);
742 assert_eq!(nf, "abb");
743 }
744 #[test]
746 fn test_srs_reduction_to_empty() {
747 let mut srs = Srs::new();
748 srs.add_rule("ab", "");
749 let nf = srs.normalize("aabb", 10);
750 assert_eq!(nf, "");
751 }
752 #[test]
754 fn test_critical_pairs_confluent() {
755 let r1 = Rule::new(f(vec![a()]), b());
756 let r2 = Rule::new(f(vec![a()]), b());
757 let pairs = critical_pairs(&r1, &r2, 100);
758 for (s, t) in &pairs {
759 assert_eq!(s, t, "non-trivial critical pair: {} β {}", s, t);
760 }
761 }
762 #[test]
764 fn test_local_confluence() {
765 let mut trs = Trs::new();
766 trs.add_rule(Rule::new(f(vec![a()]), b()));
767 assert!(check_local_confluence(&trs, 20));
768 }
769 #[test]
771 fn test_dependency_pair_graph_from_trs() {
772 let mut trs = Trs::new();
773 trs.add_rule(Rule::new(
774 Term::Fun("f".into(), vec![Term::Var(0)]),
775 Term::Fun("g".into(), vec![Term::Var(0)]),
776 ));
777 trs.add_rule(Rule::new(Term::Fun("g".into(), vec![Term::Var(0)]), a()));
778 let graph = DependencyPairGraph::from_trs(&trs);
779 assert!(!graph.pairs.is_empty());
780 }
781 #[test]
783 fn test_dependency_pair_graph_trivial_sccs() {
784 let mut trs = Trs::new();
785 trs.add_rule(Rule::new(Term::Fun("f".into(), vec![Term::Var(0)]), a()));
786 let graph = DependencyPairGraph::from_trs(&trs);
787 assert!(graph.all_sccs_trivial());
788 }
789 #[test]
791 fn test_polynomial_interpretation_termination() {
792 let mut interp = PolynomialInterpretation::new();
793 interp.set("f", vec![1, 1]);
794 let rule = Rule::new(Term::Fun("f".into(), vec![Term::Var(0)]), Term::Var(0));
795 assert!(interp.orients_rule(&rule, 5));
796 }
797 #[test]
799 fn test_polynomial_interpretation_fails() {
800 let mut interp = PolynomialInterpretation::new();
801 interp.set("f", vec![1, 1]);
802 let rule = Rule::new(
803 Term::Fun("f".into(), vec![Term::Var(0)]),
804 Term::Fun("f".into(), vec![Term::Var(0)]),
805 );
806 assert!(!interp.orients_rule(&rule, 3));
807 }
808 #[test]
810 fn test_narrowing_step() {
811 let mut trs = Trs::new();
812 trs.add_rule(Rule::new(f(vec![a()]), b()));
813 let mut ns = NarrowingSystem::new(trs);
814 let term = f(vec![Term::Var(0)]);
815 let steps = ns.narrow_step(&term);
816 assert!(!steps.is_empty());
817 assert!(steps.iter().any(|(_, t)| *t == b()));
818 }
819 #[test]
821 fn test_tree_automaton_accepts() {
822 let mut ta = TreeAutomaton::new(2);
823 ta.add_final(1);
824 ta.add_transition("a", vec![], 0);
825 ta.add_transition("b", vec![], 0);
826 ta.add_transition("f", vec![0], 1);
827 assert!(ta.accepts(&f(vec![a()])));
828 assert!(!ta.accepts(&a()));
829 }
830 #[test]
832 fn test_tree_automaton_nonempty() {
833 let mut ta = TreeAutomaton::new(2);
834 ta.add_final(1);
835 ta.add_transition("a", vec![], 0);
836 ta.add_transition("f", vec![0], 1);
837 assert!(!ta.is_empty());
838 }
839 #[test]
841 fn test_dependency_pair_graph_cycle() {
842 let mut graph = DependencyPairGraph::new();
843 let i = graph.add_pair("f", "g");
844 let j = graph.add_pair("g", "f");
845 graph.add_edge(i, j);
846 graph.add_edge(j, i);
847 assert!(!graph.all_sccs_trivial());
848 }
849 #[test]
851 fn test_polynomial_interpretation_proves_termination() {
852 let mut interp = PolynomialInterpretation::new();
853 interp.set("f", vec![1, 1]);
854 let mut trs = Trs::new();
855 trs.add_rule(Rule::new(f(vec![f(vec![x0()])]), f(vec![x0()])));
856 assert!(interp.proves_termination(&trs, 5));
857 }
858 #[test]
860 fn test_tree_automaton_empty_language() {
861 let mut ta = TreeAutomaton::new(2);
862 ta.add_final(1);
863 assert!(ta.is_empty());
864 }
865 #[test]
867 fn test_narrowing_depth_zero() {
868 let trs = Trs::new();
869 let mut ns = NarrowingSystem::new(trs);
870 let term = f(vec![a()]);
871 let results = ns.basic_narrow(&term, 0);
872 assert_eq!(results.len(), 1);
873 assert_eq!(results[0].1, term);
874 }
875}
876#[cfg(test)]
877mod tests_term_rewriting_ext {
878 use super::*;
879 #[test]
880 fn test_string_rewriting() {
881 let mut srs = StringRewritingSystem::new(vec!['a', 'b']);
882 srs.add_rule("aa", "a");
883 srs.add_rule("bb", "b");
884 let result = srs.normalize("aabb", 10);
885 assert_eq!(result, "ab", "aabb -> ab after normalizing");
886 }
887 #[test]
888 fn test_string_rewriting_no_rule() {
889 let srs = StringRewritingSystem::new(vec!['a', 'b']);
890 let result = srs.normalize("abc", 10);
891 assert_eq!(result, "abc");
892 assert_eq!(srs.num_rules(), 0);
893 }
894 #[test]
895 fn test_egraph_union_find() {
896 let mut eg = EGraph::new();
897 let n1 = eg.add_node("x");
898 let n2 = eg.add_node("y");
899 let n3 = eg.add_node("x+1");
900 assert!(!eg.are_equal(n1, n2));
901 eg.union(n1, n2);
902 assert!(eg.are_equal(n1, n2));
903 assert!(!eg.are_equal(n1, n3));
904 assert_eq!(eg.num_classes(), 3);
905 }
906 #[test]
907 fn test_rewriting_logic_theory() {
908 let mut th = RewritingLogicTheory::new();
909 th.add_sort("State");
910 th.add_equation("0 + x", "x");
911 th.add_rw_rule("step", "s β t", "t");
912 assert!(!th.is_equational());
913 assert_eq!(th.signature_size(), 2);
914 assert!(th.entailment_description().contains("1 sorts"));
915 }
916 #[test]
917 fn test_string_rewriting_equal_modulo() {
918 let mut srs = StringRewritingSystem::new(vec!['a', 'b']);
919 srs.add_rule("ab", "ba");
920 assert!(srs.are_equal_modulo("ab", "ba", 5));
921 }
922}
923#[cfg(test)]
924mod tests_term_rewriting_ext2 {
925 use super::*;
926 #[test]
927 fn test_knuth_bendix() {
928 let mut kb = KnuthBendixData::new("LPO");
929 kb.add_oriented_rule("i(i(x))", "x");
930 kb.add_oriented_rule("e * x", "x");
931 kb.add_critical_pair("i(i(x))", "x");
932 kb.mark_confluent();
933 assert!(kb.is_confluent);
934 assert_eq!(kb.num_rules(), 2);
935 assert!(kb.description().contains("confluent=true"));
936 }
937}
938#[cfg(test)]
939mod tests_term_rewriting_ext3 {
940 use super::*;
941 #[test]
942 fn test_reduction_strategy() {
943 let s = ReductionStrategy::LeftmostOutermost;
944 assert!(s.is_complete());
945 assert!(s.normalizing_for_orthogonal());
946 assert!(s.name().contains("Normal"));
947 let li = ReductionStrategy::LeftmostInnermost;
948 assert!(!li.is_complete());
949 assert_eq!(li.lambda_calculus_analog(), "Call-by-value");
950 let needed = ReductionStrategy::Needed;
951 assert!(needed.is_complete());
952 assert_eq!(needed.lambda_calculus_analog(), "Call-by-need (lazy)");
953 }
954}