1use crate::error::{ProofError, ProofResult};
32use crate::unify::{
33 apply_subst_to_expr, beta_reduce, compose_substitutions, unify_exprs, unify_pattern,
34 unify_terms, Substitution,
35};
36use crate::{DerivationTree, InferenceRule, ProofExpr, ProofGoal, ProofTerm};
37
38const DEFAULT_MAX_DEPTH: usize = 100;
40
41pub struct BackwardChainer {
46 knowledge_base: Vec<ProofExpr>,
48
49 max_depth: usize,
51
52 var_counter: usize,
54}
55
56fn term_to_expr(term: &ProofTerm) -> ProofExpr {
64 match term {
65 ProofTerm::Constant(s) => ProofExpr::Atom(s.clone()),
66 ProofTerm::Variable(s) => ProofExpr::Atom(s.clone()),
67 ProofTerm::BoundVarRef(s) => ProofExpr::Atom(s.clone()),
68 ProofTerm::Function(name, args) => {
69 if matches!(name.as_str(), "Zero" | "Succ" | "Nil" | "Cons") {
71 ProofExpr::Ctor {
72 name: name.clone(),
73 args: args.iter().map(term_to_expr).collect(),
74 }
75 } else {
76 ProofExpr::Predicate {
78 name: name.clone(),
79 args: args.clone(),
80 world: None,
81 }
82 }
83 }
84 ProofTerm::Group(terms) => {
85 if terms.len() == 1 {
87 term_to_expr(&terms[0])
88 } else {
89 ProofExpr::Predicate {
91 name: "Group".into(),
92 args: terms.clone(),
93 world: None,
94 }
95 }
96 }
97 }
98}
99
100fn exprs_structurally_equal(left: &ProofExpr, right: &ProofExpr) -> bool {
104 match (left, right) {
105 (ProofExpr::Atom(a), ProofExpr::Atom(b)) => a == b,
106
107 (ProofExpr::Ctor { name: n1, args: a1 }, ProofExpr::Ctor { name: n2, args: a2 }) => {
108 n1 == n2 && a1.len() == a2.len() && a1.iter().zip(a2).all(|(x, y)| exprs_structurally_equal(x, y))
109 }
110
111 (
112 ProofExpr::Predicate { name: n1, args: a1, .. },
113 ProofExpr::Predicate { name: n2, args: a2, .. },
114 ) => n1 == n2 && a1.len() == a2.len() && a1.iter().zip(a2).all(|(x, y)| terms_structurally_equal(x, y)),
115
116 (ProofExpr::Identity(l1, r1), ProofExpr::Identity(l2, r2)) => {
117 terms_structurally_equal(l1, l2) && terms_structurally_equal(r1, r2)
118 }
119
120 (ProofExpr::And(l1, r1), ProofExpr::And(l2, r2))
121 | (ProofExpr::Or(l1, r1), ProofExpr::Or(l2, r2))
122 | (ProofExpr::Implies(l1, r1), ProofExpr::Implies(l2, r2))
123 | (ProofExpr::Iff(l1, r1), ProofExpr::Iff(l2, r2)) => {
124 exprs_structurally_equal(l1, l2) && exprs_structurally_equal(r1, r2)
125 }
126
127 (ProofExpr::Not(a), ProofExpr::Not(b)) => exprs_structurally_equal(a, b),
128
129 (
130 ProofExpr::ForAll { variable: v1, body: b1 },
131 ProofExpr::ForAll { variable: v2, body: b2 },
132 )
133 | (
134 ProofExpr::Exists { variable: v1, body: b1 },
135 ProofExpr::Exists { variable: v2, body: b2 },
136 ) => v1 == v2 && exprs_structurally_equal(b1, b2),
137
138 (
139 ProofExpr::Lambda { variable: v1, body: b1 },
140 ProofExpr::Lambda { variable: v2, body: b2 },
141 ) => v1 == v2 && exprs_structurally_equal(b1, b2),
142
143 (ProofExpr::App(f1, a1), ProofExpr::App(f2, a2)) => {
144 exprs_structurally_equal(f1, f2) && exprs_structurally_equal(a1, a2)
145 }
146
147 (
148 ProofExpr::TypedVar { name: n1, typename: t1 },
149 ProofExpr::TypedVar { name: n2, typename: t2 },
150 ) => n1 == n2 && t1 == t2,
151
152 (
153 ProofExpr::Fixpoint { name: n1, body: b1 },
154 ProofExpr::Fixpoint { name: n2, body: b2 },
155 ) => n1 == n2 && exprs_structurally_equal(b1, b2),
156
157 _ => false,
158 }
159}
160
161fn terms_structurally_equal(left: &ProofTerm, right: &ProofTerm) -> bool {
163 match (left, right) {
164 (ProofTerm::Constant(a), ProofTerm::Constant(b)) => a == b,
165 (ProofTerm::Variable(a), ProofTerm::Variable(b)) => a == b,
166 (ProofTerm::BoundVarRef(a), ProofTerm::BoundVarRef(b)) => a == b,
167 (ProofTerm::Function(n1, a1), ProofTerm::Function(n2, a2)) => {
168 n1 == n2 && a1.len() == a2.len() && a1.iter().zip(a2).all(|(x, y)| terms_structurally_equal(x, y))
169 }
170 (ProofTerm::Group(a1), ProofTerm::Group(a2)) => {
171 a1.len() == a2.len() && a1.iter().zip(a2).all(|(x, y)| terms_structurally_equal(x, y))
172 }
173 _ => false,
174 }
175}
176
177impl BackwardChainer {
178 pub fn new() -> Self {
180 Self {
181 knowledge_base: Vec::new(),
182 max_depth: DEFAULT_MAX_DEPTH,
183 var_counter: 0,
184 }
185 }
186
187 pub fn set_max_depth(&mut self, depth: usize) {
189 self.max_depth = depth;
190 }
191
192 pub fn knowledge_base(&self) -> &[ProofExpr] {
194 &self.knowledge_base
195 }
196
197 pub fn add_axiom(&mut self, expr: ProofExpr) {
201 let abstracted = self.abstract_all_events(&expr);
203 let simplified = self.simplify_definite_description_conjunction(&abstracted);
205 self.knowledge_base.push(simplified);
206 }
207
208 pub fn prove(&mut self, goal: ProofExpr) -> ProofResult<DerivationTree> {
214 self.unify_definite_descriptions();
218
219 let abstracted_goal = self.abstract_events_only(&goal);
222 let normalized_goal = self.simplify_definite_description_conjunction(&abstracted_goal);
224 self.prove_goal(ProofGoal::new(normalized_goal), 0)
225 }
226
227 pub fn prove_with_goal(&mut self, goal: ProofGoal) -> ProofResult<DerivationTree> {
232 self.unify_definite_descriptions();
233
234 let abstracted_target = self.abstract_events_only(&goal.target);
236 let normalized_target = self.simplify_definite_description_conjunction(&abstracted_target);
237
238 let normalized_context: Vec<ProofExpr> = goal
240 .context
241 .iter()
242 .map(|expr| {
243 let abstracted = self.abstract_events_only(expr);
244 self.simplify_definite_description_conjunction(&abstracted)
245 })
246 .collect();
247
248 let normalized_goal = ProofGoal::with_context(normalized_target, normalized_context);
249 self.prove_goal(normalized_goal, 0)
250 }
251
252 fn unify_definite_descriptions(&mut self) {
261 let mut definite_descs: std::collections::HashMap<String, Vec<(usize, String, ProofExpr)>> = std::collections::HashMap::new();
263
264 for (idx, axiom) in self.knowledge_base.iter().enumerate() {
265 if let Some((pred_name, var_name, property)) = self.extract_definite_description(axiom) {
266 definite_descs.entry(pred_name).or_default().push((idx, var_name, property));
267 }
268 }
269
270 for (pred_name, descs) in definite_descs {
272 if descs.is_empty() {
273 continue;
274 }
275
276 let skolem_name = format!("the_{}", pred_name);
278 let skolem_const = ProofTerm::Constant(skolem_name.clone());
279
280 let defining_fact = ProofExpr::Predicate {
282 name: pred_name.clone(),
283 args: vec![skolem_const.clone()],
284 world: None,
285 };
286 self.knowledge_base.push(defining_fact);
287
288 let uniqueness = ProofExpr::ForAll {
292 variable: "_u".to_string(),
293 body: Box::new(ProofExpr::Implies(
294 Box::new(ProofExpr::Predicate {
295 name: pred_name.clone(),
296 args: vec![ProofTerm::Variable("_u".to_string())],
297 world: None,
298 }),
299 Box::new(ProofExpr::Identity(
300 ProofTerm::Variable("_u".to_string()),
301 skolem_const.clone(),
302 )),
303 )),
304 };
305 self.knowledge_base.push(uniqueness);
306
307 let mut indices_to_remove: Vec<usize> = Vec::new();
309 for (idx, var_name, property) in descs {
310 let substituted = self.substitute_term_in_expr(
312 &property,
313 &ProofTerm::Variable(var_name),
314 &skolem_const,
315 );
316 let normalized = self.normalize_for_proof(&substituted);
318 self.knowledge_base.push(normalized);
319 indices_to_remove.push(idx);
320 }
321
322 indices_to_remove.sort_unstable_by(|a, b| b.cmp(a));
324 for idx in indices_to_remove {
325 self.knowledge_base.remove(idx);
326 }
327 }
328 }
329
330 fn normalize_for_proof(&self, expr: &ProofExpr) -> ProofExpr {
334 match expr {
335 ProofExpr::ForAll { variable, body } => {
336 if let ProofExpr::Not(inner) = body.as_ref() {
338 if let ProofExpr::And(left, right) = inner.as_ref() {
339 return ProofExpr::ForAll {
340 variable: variable.clone(),
341 body: Box::new(ProofExpr::Implies(
342 Box::new(self.normalize_for_proof(left)),
343 Box::new(ProofExpr::Not(Box::new(self.normalize_for_proof(right)))),
344 )),
345 };
346 }
347 }
348 ProofExpr::ForAll {
349 variable: variable.clone(),
350 body: Box::new(self.normalize_for_proof(body)),
351 }
352 }
353 ProofExpr::And(left, right) => ProofExpr::And(
354 Box::new(self.normalize_for_proof(left)),
355 Box::new(self.normalize_for_proof(right)),
356 ),
357 ProofExpr::Or(left, right) => ProofExpr::Or(
358 Box::new(self.normalize_for_proof(left)),
359 Box::new(self.normalize_for_proof(right)),
360 ),
361 ProofExpr::Implies(left, right) => ProofExpr::Implies(
362 Box::new(self.normalize_for_proof(left)),
363 Box::new(self.normalize_for_proof(right)),
364 ),
365 ProofExpr::Not(inner) => ProofExpr::Not(Box::new(self.normalize_for_proof(inner))),
366 ProofExpr::Exists { variable, body } => ProofExpr::Exists {
367 variable: variable.clone(),
368 body: Box::new(self.normalize_for_proof(body)),
369 },
370 other => other.clone(),
371 }
372 }
373
374 fn extract_definite_description(&self, expr: &ProofExpr) -> Option<(String, String, ProofExpr)> {
379 let (var, body) = match expr {
381 ProofExpr::Exists { variable, body } => (variable.clone(), body.as_ref()),
382 _ => return None,
383 };
384
385 let (defining_part, property) = match body {
387 ProofExpr::And(left, right) => (left.as_ref(), right.as_ref().clone()),
388 _ => return None,
389 };
390
391 let (type_pred, uniqueness) = match defining_part {
393 ProofExpr::And(left, right) => (left.as_ref(), right.as_ref()),
394 _ => return None,
395 };
396
397 let pred_name = match type_pred {
399 ProofExpr::Predicate { name, args, .. } if args.len() == 1 => {
400 if let ProofTerm::Variable(v) = &args[0] {
402 if v == &var {
403 name.clone()
404 } else {
405 return None;
406 }
407 } else {
408 return None;
409 }
410 }
411 _ => return None,
412 };
413
414 match uniqueness {
416 ProofExpr::ForAll { variable: _, body: inner_body } => {
417 match inner_body.as_ref() {
418 ProofExpr::Implies(ante, cons) => {
419 if let ProofExpr::Predicate { name, .. } = ante.as_ref() {
421 if name != &pred_name {
422 return None;
423 }
424 } else {
425 return None;
426 }
427 if !matches!(cons.as_ref(), ProofExpr::Identity(_, _)) {
429 return None;
430 }
431 }
432 _ => return None,
433 }
434 }
435 _ => return None,
436 }
437
438 Some((pred_name, var, property))
439 }
440
441 fn prove_goal(&mut self, goal: ProofGoal, depth: usize) -> ProofResult<DerivationTree> {
443 if depth > self.max_depth {
445 return Err(ProofError::DepthExceeded);
446 }
447
448 if let Some((_, typename)) = self.find_typed_var(&goal.target) {
452 let is_known_inductive = matches!(typename.as_str(), "Nat" | "List");
455
456 if let Some(tree) = self.try_structural_induction(&goal, depth)? {
457 return Ok(tree);
458 }
459
460 if is_known_inductive {
463 return Err(ProofError::NoProofFound);
464 }
465 }
467
468 if let Some(tree) = self.try_reflexivity(&goal)? {
471 return Ok(tree);
472 }
473
474 if let Some(tree) = self.try_match_fact(&goal)? {
476 return Ok(tree);
477 }
478
479 if let Some(tree) = self.try_intro_rules(&goal, depth)? {
481 return Ok(tree);
482 }
483
484 if let Some(tree) = self.try_backward_chain(&goal, depth)? {
486 return Ok(tree);
487 }
488
489 if let Some(tree) = self.try_modus_tollens(&goal, depth)? {
491 return Ok(tree);
492 }
493
494 if let Some(tree) = self.try_universal_inst(&goal, depth)? {
496 return Ok(tree);
497 }
498
499 if let Some(tree) = self.try_existential_intro(&goal, depth)? {
501 return Ok(tree);
502 }
503
504 if let Some(tree) = self.try_disjunction_elimination(&goal, depth)? {
506 return Ok(tree);
507 }
508
509 if let Some(tree) = self.try_reductio_ad_absurdum(&goal, depth)? {
512 return Ok(tree);
513 }
514
515 if let Some(tree) = self.try_existential_elimination(&goal, depth)? {
518 return Ok(tree);
519 }
520
521 if let Some(tree) = self.try_equality_rewrite(&goal, depth)? {
523 return Ok(tree);
524 }
525
526 #[cfg(feature = "verification")]
528 if let Some(tree) = self.try_oracle_fallback(&goal)? {
529 return Ok(tree);
530 }
531
532 Err(ProofError::NoProofFound)
534 }
535
536 fn try_reflexivity(&self, goal: &ProofGoal) -> ProofResult<Option<DerivationTree>> {
545 if let ProofExpr::Identity(left_term, right_term) = &goal.target {
546 let left_expr = term_to_expr(left_term);
548 let right_expr = term_to_expr(right_term);
549
550 let left_normal = beta_reduce(&left_expr);
552 let right_normal = beta_reduce(&right_expr);
553
554 if exprs_structurally_equal(&left_normal, &right_normal) {
556 return Ok(Some(DerivationTree::leaf(
557 goal.target.clone(),
558 InferenceRule::Reflexivity,
559 )));
560 }
561 }
562 Ok(None)
563 }
564
565 fn try_match_fact(&self, goal: &ProofGoal) -> ProofResult<Option<DerivationTree>> {
571 for fact in goal.context.iter().chain(self.knowledge_base.iter()) {
573 if let Ok(subst) = unify_exprs(&goal.target, fact) {
574 return Ok(Some(
575 DerivationTree::leaf(goal.target.clone(), InferenceRule::PremiseMatch)
576 .with_substitution(subst),
577 ));
578 }
579 }
580 Ok(None)
581 }
582
583 fn try_intro_rules(
589 &mut self,
590 goal: &ProofGoal,
591 depth: usize,
592 ) -> ProofResult<Option<DerivationTree>> {
593 match &goal.target {
594 ProofExpr::And(left, right) => {
596 let left_goal = ProofGoal::with_context((**left).clone(), goal.context.clone());
597 let right_goal = ProofGoal::with_context((**right).clone(), goal.context.clone());
598
599 if let (Ok(left_proof), Ok(right_proof)) = (
601 self.prove_goal(left_goal, depth + 1),
602 self.prove_goal(right_goal, depth + 1),
603 ) {
604 return Ok(Some(DerivationTree::new(
605 goal.target.clone(),
606 InferenceRule::ConjunctionIntro,
607 vec![left_proof, right_proof],
608 )));
609 }
610 }
611
612 ProofExpr::Or(left, right) => {
614 let left_goal = ProofGoal::with_context((**left).clone(), goal.context.clone());
616 if let Ok(left_proof) = self.prove_goal(left_goal, depth + 1) {
617 return Ok(Some(DerivationTree::new(
618 goal.target.clone(),
619 InferenceRule::DisjunctionIntro,
620 vec![left_proof],
621 )));
622 }
623
624 let right_goal = ProofGoal::with_context((**right).clone(), goal.context.clone());
626 if let Ok(right_proof) = self.prove_goal(right_goal, depth + 1) {
627 return Ok(Some(DerivationTree::new(
628 goal.target.clone(),
629 InferenceRule::DisjunctionIntro,
630 vec![right_proof],
631 )));
632 }
633 }
634
635 ProofExpr::Not(inner) => {
637 if let ProofExpr::Not(core) = &**inner {
638 let core_goal = ProofGoal::with_context((**core).clone(), goal.context.clone());
639 if let Ok(core_proof) = self.prove_goal(core_goal, depth + 1) {
640 return Ok(Some(DerivationTree::new(
641 goal.target.clone(),
642 InferenceRule::DoubleNegation,
643 vec![core_proof],
644 )));
645 }
646 }
647 }
648
649 _ => {}
650 }
651
652 Ok(None)
653 }
654
655 fn try_backward_chain(
661 &mut self,
662 goal: &ProofGoal,
663 depth: usize,
664 ) -> ProofResult<Option<DerivationTree>> {
665 let implications: Vec<(usize, ProofExpr)> = self
667 .knowledge_base
668 .iter()
669 .enumerate()
670 .filter_map(|(idx, expr)| {
671 if let ProofExpr::Implies(_, _) = expr {
672 Some((idx, expr.clone()))
673 } else {
674 None
675 }
676 })
677 .collect();
678
679 for (idx, impl_expr) in implications {
680 if let ProofExpr::Implies(antecedent, consequent) = &impl_expr {
681 let renamed = self.rename_variables(&impl_expr);
683 if let ProofExpr::Implies(ant, con) = renamed {
684 if let Ok(subst) = unify_exprs(&goal.target, &con) {
686 let new_antecedent = apply_subst_to_expr(&ant, &subst);
688
689 let ant_goal =
691 ProofGoal::with_context(new_antecedent, goal.context.clone());
692
693 if let Ok(ant_proof) = self.prove_goal(ant_goal, depth + 1) {
694 let impl_leaf = DerivationTree::leaf(
696 impl_expr.clone(),
697 InferenceRule::PremiseMatch,
698 );
699
700 return Ok(Some(
701 DerivationTree::new(
702 goal.target.clone(),
703 InferenceRule::ModusPonens,
704 vec![impl_leaf, ant_proof],
705 )
706 .with_substitution(subst),
707 ));
708 }
709 }
710 }
711 }
712 }
713
714 Ok(None)
715 }
716
717 fn try_modus_tollens(
728 &mut self,
729 goal: &ProofGoal,
730 depth: usize,
731 ) -> ProofResult<Option<DerivationTree>> {
732 let inner_goal = match &goal.target {
734 ProofExpr::Not(inner) => (**inner).clone(),
735 _ => return Ok(None),
736 };
737
738 let implications: Vec<ProofExpr> = self
740 .knowledge_base
741 .iter()
742 .chain(goal.context.iter())
743 .flat_map(|expr| {
744 match expr {
745 ProofExpr::Implies(_, _) => vec![expr.clone()],
746 ProofExpr::ForAll { body, .. } => {
747 if let ProofExpr::Implies(_, _) = body.as_ref() {
749 vec![*body.clone()]
750 } else {
751 vec![]
752 }
753 }
754 _ => vec![],
755 }
756 })
757 .collect();
758
759 let negations: Vec<ProofExpr> = self
761 .knowledge_base
762 .iter()
763 .chain(goal.context.iter())
764 .filter_map(|expr| {
765 if let ProofExpr::Not(inner) = expr {
766 Some((**inner).clone())
767 } else {
768 None
769 }
770 })
771 .collect();
772
773 for impl_expr in &implications {
775 if let ProofExpr::Implies(antecedent, consequent) = impl_expr {
776 if let Ok(subst) = unify_exprs(&inner_goal, antecedent) {
778 let q = apply_subst_to_expr(consequent, &subst);
780
781 for negated in &negations {
783 if exprs_structurally_equal(negated, &q) {
784 let impl_leaf = DerivationTree::leaf(
786 impl_expr.clone(),
787 InferenceRule::PremiseMatch,
788 );
789 let neg_q_leaf = DerivationTree::leaf(
790 ProofExpr::Not(Box::new(q.clone())),
791 InferenceRule::PremiseMatch,
792 );
793
794 return Ok(Some(
795 DerivationTree::new(
796 goal.target.clone(),
797 InferenceRule::ModusTollens,
798 vec![impl_leaf, neg_q_leaf],
799 )
800 .with_substitution(subst),
801 ));
802 }
803 }
804
805 let neg_q_goal = ProofGoal::with_context(
807 ProofExpr::Not(Box::new(q.clone())),
808 goal.context.clone(),
809 );
810
811 if let Ok(neg_q_proof) = self.prove_goal(neg_q_goal, depth + 1) {
812 let impl_leaf = DerivationTree::leaf(
814 impl_expr.clone(),
815 InferenceRule::PremiseMatch,
816 );
817
818 return Ok(Some(
819 DerivationTree::new(
820 goal.target.clone(),
821 InferenceRule::ModusTollens,
822 vec![impl_leaf, neg_q_proof],
823 )
824 .with_substitution(subst),
825 ));
826 }
827 }
828 }
829 }
830
831 Ok(None)
832 }
833
834 fn try_universal_inst(
840 &mut self,
841 goal: &ProofGoal,
842 depth: usize,
843 ) -> ProofResult<Option<DerivationTree>> {
844 let universals: Vec<(usize, ProofExpr)> = self
846 .knowledge_base
847 .iter()
848 .enumerate()
849 .filter_map(|(idx, expr)| {
850 if let ProofExpr::ForAll { .. } = expr {
851 Some((idx, expr.clone()))
852 } else {
853 None
854 }
855 })
856 .collect();
857
858 for (idx, forall_expr) in universals {
859 if let ProofExpr::ForAll { variable, body } = &forall_expr {
860 let renamed = self.rename_variables(&forall_expr);
862 if let ProofExpr::ForAll {
863 variable: var,
864 body: renamed_body,
865 } = renamed
866 {
867 if let Ok(subst) = unify_exprs(&goal.target, &renamed_body) {
869 if let Some(witness) = subst.get(&var) {
871 let witness_str = format!("{}", witness);
872
873 let universal_leaf = DerivationTree::leaf(
875 forall_expr.clone(),
876 InferenceRule::PremiseMatch,
877 );
878
879 return Ok(Some(
880 DerivationTree::new(
881 goal.target.clone(),
882 InferenceRule::UniversalInst(witness_str),
883 vec![universal_leaf],
884 )
885 .with_substitution(subst),
886 ));
887 }
888 }
889
890 if let ProofExpr::Implies(ant, con) = &*renamed_body {
893 if let Ok(subst) = unify_exprs(&goal.target, con) {
894 let new_antecedent = apply_subst_to_expr(ant, &subst);
896
897 let ant_goal =
898 ProofGoal::with_context(new_antecedent, goal.context.clone());
899
900 if let Ok(ant_proof) = self.prove_goal(ant_goal, depth + 1) {
901 let witness_str = subst
903 .get(&var)
904 .map(|t| format!("{}", t))
905 .unwrap_or_else(|| var.clone());
906
907 let universal_leaf = DerivationTree::leaf(
909 forall_expr.clone(),
910 InferenceRule::PremiseMatch,
911 );
912
913 let inst_node = DerivationTree::new(
914 apply_subst_to_expr(&renamed_body, &subst),
915 InferenceRule::UniversalInst(witness_str),
916 vec![universal_leaf],
917 );
918
919 return Ok(Some(
920 DerivationTree::new(
921 goal.target.clone(),
922 InferenceRule::ModusPonens,
923 vec![inst_node, ant_proof],
924 )
925 .with_substitution(subst),
926 ));
927 }
928 }
929 }
930 }
931 }
932 }
933
934 Ok(None)
935 }
936
937 fn try_existential_intro(
943 &mut self,
944 goal: &ProofGoal,
945 depth: usize,
946 ) -> ProofResult<Option<DerivationTree>> {
947 if let ProofExpr::Exists { variable, body } = &goal.target {
948 let witnesses = self.collect_witnesses();
951
952 for witness in witnesses {
953 let mut subst = Substitution::new();
955 subst.insert(variable.clone(), witness.clone());
956
957 let instantiated = apply_subst_to_expr(body, &subst);
959
960 let inst_goal = ProofGoal::with_context(instantiated, goal.context.clone());
962
963 if let Ok(body_proof) = self.prove_goal(inst_goal, depth + 1) {
964 let witness_str = format!("{}", witness);
965 let witness_type = extract_type_from_exists_body(body)
967 .unwrap_or_else(|| "Nat".to_string());
968 return Ok(Some(DerivationTree::new(
969 goal.target.clone(),
970 InferenceRule::ExistentialIntro {
971 witness: witness_str,
972 witness_type,
973 },
974 vec![body_proof],
975 )));
976 }
977 }
978 }
979
980 Ok(None)
981 }
982
983 fn try_disjunction_elimination(
993 &mut self,
994 goal: &ProofGoal,
995 _depth: usize,
996 ) -> ProofResult<Option<DerivationTree>> {
997 let disjunctions: Vec<(ProofExpr, ProofExpr, ProofExpr)> = self
999 .knowledge_base
1000 .iter()
1001 .chain(goal.context.iter())
1002 .filter_map(|expr| {
1003 if let ProofExpr::Or(left, right) = expr {
1004 Some((expr.clone(), (**left).clone(), (**right).clone()))
1005 } else {
1006 None
1007 }
1008 })
1009 .collect();
1010
1011 let negations: Vec<ProofExpr> = self
1013 .knowledge_base
1014 .iter()
1015 .chain(goal.context.iter())
1016 .filter_map(|expr| {
1017 if let ProofExpr::Not(inner) = expr {
1018 Some((**inner).clone())
1019 } else {
1020 None
1021 }
1022 })
1023 .collect();
1024
1025 for (disj_expr, left, right) in &disjunctions {
1027 for negated in &negations {
1029 if exprs_structurally_equal(negated, left) {
1030 if let Ok(subst) = unify_exprs(&goal.target, right) {
1033 let disj_leaf = DerivationTree::leaf(
1034 disj_expr.clone(),
1035 InferenceRule::PremiseMatch,
1036 );
1037 let neg_leaf = DerivationTree::leaf(
1038 ProofExpr::Not(Box::new(left.clone())),
1039 InferenceRule::PremiseMatch,
1040 );
1041 return Ok(Some(
1042 DerivationTree::new(
1043 goal.target.clone(),
1044 InferenceRule::DisjunctionElim,
1045 vec![disj_leaf, neg_leaf],
1046 )
1047 .with_substitution(subst),
1048 ));
1049 }
1050 }
1051
1052 if exprs_structurally_equal(negated, right) {
1054 if let Ok(subst) = unify_exprs(&goal.target, left) {
1057 let disj_leaf = DerivationTree::leaf(
1058 disj_expr.clone(),
1059 InferenceRule::PremiseMatch,
1060 );
1061 let neg_leaf = DerivationTree::leaf(
1062 ProofExpr::Not(Box::new(right.clone())),
1063 InferenceRule::PremiseMatch,
1064 );
1065 return Ok(Some(
1066 DerivationTree::new(
1067 goal.target.clone(),
1068 InferenceRule::DisjunctionElim,
1069 vec![disj_leaf, neg_leaf],
1070 )
1071 .with_substitution(subst),
1072 ));
1073 }
1074 }
1075 }
1076 }
1077
1078 Ok(None)
1079 }
1080
1081 fn try_reductio_ad_absurdum(
1093 &mut self,
1094 goal: &ProofGoal,
1095 depth: usize,
1096 ) -> ProofResult<Option<DerivationTree>> {
1097 let assumed = match &goal.target {
1099 ProofExpr::Not(inner) => (**inner).clone(),
1100 _ => return Ok(None),
1101 };
1102
1103 if depth > 5 {
1105 return Ok(None);
1106 }
1107
1108 if let ProofExpr::Exists { .. } = &assumed {
1111 return self.try_existence_negation_proof(&goal, &assumed, depth);
1112 }
1113
1114 if self.contains_quantifier(&assumed) {
1117 return Ok(None);
1118 }
1119
1120 let mut extended_context = goal.context.clone();
1122 extended_context.push(assumed.clone());
1123
1124 let skolemized = self.skolemize_existential(&assumed);
1126 for sk in &skolemized {
1127 extended_context.push(sk.clone());
1128 }
1129
1130 if let Some(contradiction_proof) = self.find_contradiction(&extended_context, depth)? {
1133 let assumption_leaf = DerivationTree::leaf(
1135 assumed.clone(),
1136 InferenceRule::PremiseMatch,
1137 );
1138
1139 return Ok(Some(DerivationTree::new(
1140 goal.target.clone(),
1141 InferenceRule::ReductioAdAbsurdum,
1142 vec![assumption_leaf, contradiction_proof],
1143 )));
1144 }
1145
1146 Ok(None)
1147 }
1148
1149 fn try_existence_negation_proof(
1161 &mut self,
1162 goal: &ProofGoal,
1163 assumed_existence: &ProofExpr,
1164 depth: usize,
1165 ) -> ProofResult<Option<DerivationTree>> {
1166 let witness_facts = self.skolemize_existential(assumed_existence);
1168
1169 if witness_facts.is_empty() {
1170 return Ok(None);
1171 }
1172
1173 let mut extended_context = goal.context.clone();
1175 extended_context.push(assumed_existence.clone());
1176
1177 for fact in &witness_facts {
1179 let abstracted = self.abstract_all_events(fact);
1180 if !extended_context.contains(&abstracted) {
1181 extended_context.push(abstracted);
1182 }
1183 if !extended_context.contains(fact) {
1184 extended_context.push(fact.clone());
1185 }
1186 }
1187
1188 let mut skolem_constants = self.extract_skolem_constants(&witness_facts);
1190
1191 let kb_skolemized = self.skolemize_kb_existentials();
1196 for fact in &kb_skolemized {
1197 let abstracted = self.abstract_all_events(fact);
1198 if !extended_context.contains(&abstracted) {
1199 extended_context.push(abstracted);
1200 }
1201 if !extended_context.contains(fact) {
1202 extended_context.push(fact.clone());
1203 }
1204 }
1205
1206 let kb_skolems = self.extract_skolem_constants(&kb_skolemized);
1208 for sk in kb_skolems {
1209 if !skolem_constants.contains(&sk) {
1210 skolem_constants.push(sk);
1211 }
1212 }
1213
1214 for expr in &self.knowledge_base {
1217 self.collect_unified_constants(expr, &mut skolem_constants);
1218 }
1219
1220 let instantiated = self.instantiate_universals_with_constants(
1222 &extended_context,
1223 &skolem_constants,
1224 );
1225 for inst in &instantiated {
1226 let abstracted = self.abstract_all_events(inst);
1227 if !extended_context.contains(&abstracted) {
1228 extended_context.push(abstracted);
1229 }
1230 }
1231
1232 let kb_instantiated = self.instantiate_kb_universals_with_constants(&skolem_constants);
1234 for inst in &kb_instantiated {
1235 let abstracted = self.abstract_all_events(inst);
1236 if !extended_context.contains(&abstracted) {
1237 extended_context.push(abstracted);
1238 }
1239 }
1240
1241 let derived_equalities = self.derive_equalities_from_uniqueness_constraints(
1246 &extended_context,
1247 &skolem_constants,
1248 );
1249
1250 for eq in &derived_equalities {
1252 if !extended_context.contains(eq) {
1253 extended_context.push(eq.clone());
1254 }
1255 }
1256
1257 let unified_context = self.apply_equalities_to_context(&extended_context, &derived_equalities);
1260
1261 if let Some(contradiction_proof) = self.find_contradiction(&unified_context, depth)? {
1263 let assumption_leaf = DerivationTree::leaf(
1264 assumed_existence.clone(),
1265 InferenceRule::PremiseMatch,
1266 );
1267
1268 return Ok(Some(DerivationTree::new(
1269 goal.target.clone(),
1270 InferenceRule::ReductioAdAbsurdum,
1271 vec![assumption_leaf, contradiction_proof],
1272 )));
1273 }
1274
1275 if let Some(case_proof) = self.try_case_analysis_contradiction(&unified_context, &skolem_constants, depth)? {
1277 let assumption_leaf = DerivationTree::leaf(
1278 assumed_existence.clone(),
1279 InferenceRule::PremiseMatch,
1280 );
1281
1282 return Ok(Some(DerivationTree::new(
1283 goal.target.clone(),
1284 InferenceRule::ReductioAdAbsurdum,
1285 vec![assumption_leaf, case_proof],
1286 )));
1287 }
1288
1289 Ok(None)
1290 }
1291
1292 fn skolemize_kb_existentials(&mut self) -> Vec<ProofExpr> {
1298 let mut results = Vec::new();
1299
1300 for expr in &self.knowledge_base.clone() {
1301 if let ProofExpr::Exists { .. } = expr {
1302 let skolemized = self.skolemize_existential(expr);
1303 results.extend(skolemized);
1304 }
1305 }
1306
1307 results
1308 }
1309
1310 fn derive_equalities_from_uniqueness_constraints(
1322 &self,
1323 context: &[ProofExpr],
1324 skolem_constants: &[String],
1325 ) -> Vec<ProofExpr> {
1326 let mut equalities = Vec::new();
1327
1328 let uniqueness_constraints = self.extract_uniqueness_constraints(context);
1331
1332 for skolem in skolem_constants {
1335 for (predicate_name, unique_entity) in &uniqueness_constraints {
1336 let skolem_term = ProofTerm::Constant(skolem.clone());
1338 let skolem_satisfies_predicate = context.iter().any(|expr| {
1339 self.predicate_matches(expr, predicate_name, &skolem_term)
1340 });
1341
1342 if skolem_satisfies_predicate {
1343 let equality = ProofExpr::Identity(
1345 skolem_term.clone(),
1346 unique_entity.clone(),
1347 );
1348 if !equalities.contains(&equality) {
1349 equalities.push(equality);
1350 }
1351
1352 let sym_equality = ProofExpr::Identity(
1354 unique_entity.clone(),
1355 skolem_term.clone(),
1356 );
1357 if !equalities.contains(&sym_equality) {
1358 equalities.push(sym_equality);
1359 }
1360 }
1361 }
1362 }
1363
1364 let mut transitive_equalities = Vec::new();
1366 for eq1 in &equalities {
1367 if let ProofExpr::Identity(t1, t2) = eq1 {
1368 for eq2 in &equalities {
1369 if let ProofExpr::Identity(t3, t4) = eq2 {
1370 if t1 == t3 && t2 != t4 {
1372 let trans_eq = ProofExpr::Identity(t2.clone(), t4.clone());
1373 if !equalities.contains(&trans_eq) && !transitive_equalities.contains(&trans_eq) {
1374 transitive_equalities.push(trans_eq);
1375 }
1376 }
1377 if t1 == t4 && t2 != t3 {
1379 let trans_eq = ProofExpr::Identity(t2.clone(), t3.clone());
1380 if !equalities.contains(&trans_eq) && !transitive_equalities.contains(&trans_eq) {
1381 transitive_equalities.push(trans_eq);
1382 }
1383 }
1384 }
1385 }
1386 }
1387 }
1388 equalities.extend(transitive_equalities);
1389
1390 equalities
1391 }
1392
1393 fn extract_uniqueness_constraints(&self, context: &[ProofExpr]) -> Vec<(String, ProofTerm)> {
1398 let mut constraints = Vec::new();
1399
1400 for expr in context.iter().chain(self.knowledge_base.iter()) {
1401 self.extract_uniqueness_from_expr(expr, &mut constraints);
1402 }
1403
1404 constraints
1405 }
1406
1407 fn extract_uniqueness_from_expr(&self, expr: &ProofExpr, constraints: &mut Vec<(String, ProofTerm)>) {
1409 match expr {
1410 ProofExpr::ForAll { variable, body } => {
1412 if let ProofExpr::Implies(ante, cons) = body.as_ref() {
1413 if let ProofExpr::Identity(left, right) = cons.as_ref() {
1414 let var_term = ProofTerm::Variable(variable.clone());
1416 if left == &var_term {
1417 if let Some(pred_name) = self.extract_unary_predicate_name(ante, variable) {
1419 constraints.push((pred_name, right.clone()));
1421 }
1422 } else if right == &var_term {
1423 if let Some(pred_name) = self.extract_unary_predicate_name(ante, variable) {
1425 constraints.push((pred_name, left.clone()));
1426 }
1427 }
1428 }
1429 }
1430 self.extract_uniqueness_from_expr(body, constraints);
1432 }
1433
1434 ProofExpr::And(left, right) => {
1436 self.extract_uniqueness_from_expr(left, constraints);
1437 self.extract_uniqueness_from_expr(right, constraints);
1438 }
1439
1440 ProofExpr::Exists { body, .. } => {
1442 self.extract_uniqueness_from_expr(body, constraints);
1443 }
1444
1445 _ => {}
1446 }
1447 }
1448
1449 fn extract_unary_predicate_name(&self, expr: &ProofExpr, var: &str) -> Option<String> {
1453 match expr {
1454 ProofExpr::Predicate { name, args, .. } => {
1455 if args.len() == 1 {
1456 if let ProofTerm::Variable(v) = &args[0] {
1457 if v == var {
1458 return Some(name.clone());
1459 }
1460 }
1461 }
1462 None
1463 }
1464 _ => None,
1465 }
1466 }
1467
1468 fn predicate_matches(&self, expr: &ProofExpr, pred_name: &str, term: &ProofTerm) -> bool {
1470 match expr {
1471 ProofExpr::Predicate { name, args, .. } => {
1472 name == pred_name && args.len() == 1 && &args[0] == term
1473 }
1474 _ => false,
1475 }
1476 }
1477
1478 fn apply_equalities_to_context(
1483 &self,
1484 context: &[ProofExpr],
1485 equalities: &[ProofExpr],
1486 ) -> Vec<ProofExpr> {
1487 if equalities.is_empty() {
1488 return context.to_vec();
1489 }
1490
1491 let mut substitutions: Vec<(&ProofTerm, &ProofTerm)> = Vec::new();
1494 for eq in equalities {
1495 if let ProofExpr::Identity(t1, t2) = eq {
1496 if let ProofTerm::Constant(c) = t1 {
1498 if c.starts_with("sk_") {
1499 substitutions.push((t2, t1)); continue;
1501 }
1502 }
1503 if let ProofTerm::Constant(c) = t2 {
1504 if c.starts_with("sk_") {
1505 substitutions.push((t1, t2)); continue;
1507 }
1508 }
1509 substitutions.push((t2, t1));
1511 }
1512 }
1513
1514 let mut unified_context = Vec::new();
1516 for expr in context {
1517 let mut unified = expr.clone();
1518 for (from, to) in &substitutions {
1519 unified = self.substitute_term_in_expr(&unified, from, to);
1520 }
1521 let abstracted = self.abstract_all_events(&unified);
1523 if !unified_context.contains(&unified) {
1524 unified_context.push(unified);
1525 }
1526 if !unified_context.contains(&abstracted) {
1527 unified_context.push(abstracted);
1528 }
1529 }
1530
1531 for expr in context {
1534 if let ProofExpr::ForAll { variable, body } = expr {
1535 if let ProofExpr::Implies(_, _) = body.as_ref() {
1536 for (from, to) in &substitutions {
1538 if let ProofTerm::Constant(c) = to {
1539 if c.starts_with("sk_") {
1540 let mut subst = Substitution::new();
1542 subst.insert(variable.clone(), (*to).clone());
1543 let instantiated = apply_subst_to_expr(body, &subst);
1544 let abstracted = self.abstract_all_events(&instantiated);
1545 if !unified_context.contains(&abstracted) {
1546 unified_context.push(abstracted);
1547 }
1548 }
1549 }
1550 }
1551 }
1552 }
1553 }
1554
1555 unified_context
1556 }
1557
1558 fn extract_skolem_constants(&self, exprs: &[ProofExpr]) -> Vec<String> {
1560 let mut constants = Vec::new();
1561 for expr in exprs {
1562 self.collect_skolem_constants_from_expr(expr, &mut constants);
1563 }
1564 constants.sort();
1565 constants.dedup();
1566 constants
1567 }
1568
1569 fn collect_skolem_constants_from_expr(&self, expr: &ProofExpr, constants: &mut Vec<String>) {
1571 match expr {
1572 ProofExpr::Predicate { args, .. } => {
1573 for arg in args {
1574 self.collect_skolem_constants_from_term(arg, constants);
1575 }
1576 }
1577 ProofExpr::And(l, r) | ProofExpr::Or(l, r) | ProofExpr::Implies(l, r) | ProofExpr::Iff(l, r) => {
1578 self.collect_skolem_constants_from_expr(l, constants);
1579 self.collect_skolem_constants_from_expr(r, constants);
1580 }
1581 ProofExpr::Not(inner) => {
1582 self.collect_skolem_constants_from_expr(inner, constants);
1583 }
1584 ProofExpr::Identity(l, r) => {
1585 self.collect_skolem_constants_from_term(l, constants);
1586 self.collect_skolem_constants_from_term(r, constants);
1587 }
1588 ProofExpr::NeoEvent { roles, .. } => {
1589 for (_, term) in roles {
1590 self.collect_skolem_constants_from_term(term, constants);
1591 }
1592 }
1593 _ => {}
1594 }
1595 }
1596
1597 fn collect_unified_constants(&self, expr: &ProofExpr, constants: &mut Vec<String>) {
1601 match expr {
1602 ProofExpr::Predicate { args, .. } => {
1603 for arg in args {
1604 if let ProofTerm::Constant(name) = arg {
1605 if name.starts_with("the_") && !constants.contains(name) {
1606 constants.push(name.clone());
1607 }
1608 }
1609 }
1610 }
1611 ProofExpr::And(left, right) | ProofExpr::Or(left, right) |
1612 ProofExpr::Implies(left, right) | ProofExpr::Iff(left, right) => {
1613 self.collect_unified_constants(left, constants);
1614 self.collect_unified_constants(right, constants);
1615 }
1616 ProofExpr::Not(inner) => self.collect_unified_constants(inner, constants),
1617 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
1618 self.collect_unified_constants(body, constants);
1619 }
1620 ProofExpr::Identity(t1, t2) => {
1621 if let ProofTerm::Constant(name) = t1 {
1622 if name.starts_with("the_") && !constants.contains(name) {
1623 constants.push(name.clone());
1624 }
1625 }
1626 if let ProofTerm::Constant(name) = t2 {
1627 if name.starts_with("the_") && !constants.contains(name) {
1628 constants.push(name.clone());
1629 }
1630 }
1631 }
1632 _ => {}
1633 }
1634 }
1635
1636 fn collect_skolem_constants_from_term(&self, term: &ProofTerm, constants: &mut Vec<String>) {
1637 match term {
1638 ProofTerm::Constant(name) if name.starts_with("sk_") => {
1639 constants.push(name.clone());
1640 }
1641 ProofTerm::Function(_, args) => {
1642 for arg in args {
1643 self.collect_skolem_constants_from_term(arg, constants);
1644 }
1645 }
1646 ProofTerm::Group(terms) => {
1647 for t in terms {
1648 self.collect_skolem_constants_from_term(t, constants);
1649 }
1650 }
1651 _ => {}
1652 }
1653 }
1654
1655 fn instantiate_universals_with_constants(
1657 &self,
1658 context: &[ProofExpr],
1659 constants: &[String],
1660 ) -> Vec<ProofExpr> {
1661 let mut results = Vec::new();
1662
1663 for expr in context {
1664 if let ProofExpr::ForAll { variable, body } = expr {
1665 for constant in constants {
1666 let mut subst = Substitution::new();
1667 subst.insert(variable.clone(), ProofTerm::Constant(constant.clone()));
1668 let instantiated = apply_subst_to_expr(body, &subst);
1669 results.push(instantiated);
1670 }
1671 }
1672 }
1673
1674 results
1675 }
1676
1677 fn instantiate_kb_universals_with_constants(&self, constants: &[String]) -> Vec<ProofExpr> {
1679 let mut results = Vec::new();
1680
1681 for expr in &self.knowledge_base {
1682 if let ProofExpr::ForAll { variable, body } = expr {
1683 for constant in constants {
1684 let mut subst = Substitution::new();
1685 subst.insert(variable.clone(), ProofTerm::Constant(constant.clone()));
1686 let instantiated = apply_subst_to_expr(body, &subst);
1687 results.push(instantiated);
1688 }
1689 }
1690 }
1691
1692 results
1693 }
1694
1695 fn try_case_analysis_contradiction(
1707 &mut self,
1708 context: &[ProofExpr],
1709 skolem_constants: &[String],
1710 depth: usize,
1711 ) -> ProofResult<Option<DerivationTree>> {
1712 let candidates = self.find_case_split_candidates(context, skolem_constants);
1715
1716 for candidate in candidates {
1717 let mut context_with_pos = context.to_vec();
1719 if !context_with_pos.contains(&candidate) {
1720 context_with_pos.push(candidate.clone());
1721 }
1722
1723 let negated = ProofExpr::Not(Box::new(candidate.clone()));
1725 let mut context_with_neg = context.to_vec();
1726 if !context_with_neg.contains(&negated) {
1727 context_with_neg.push(negated.clone());
1728 }
1729
1730 let case1_contradiction = self.find_contradiction(&context_with_pos, depth)?;
1732 let case2_contradiction = self.find_contradiction(&context_with_neg, depth)?;
1733
1734 if let (Some(case1_proof), Some(case2_proof)) = (case1_contradiction, case2_contradiction) {
1736 let case1_tree = DerivationTree::new(
1738 ProofExpr::Atom("⊥".into()),
1739 InferenceRule::PremiseMatch,
1740 vec![case1_proof],
1741 );
1742 let case2_tree = DerivationTree::new(
1743 ProofExpr::Atom("⊥".into()),
1744 InferenceRule::PremiseMatch,
1745 vec![case2_proof],
1746 );
1747
1748 return Ok(Some(DerivationTree::new(
1749 ProofExpr::Atom("⊥".into()),
1750 InferenceRule::CaseAnalysis {
1751 case_formula: format!("{}", candidate),
1752 },
1753 vec![case1_tree, case2_tree],
1754 )));
1755 }
1756 }
1757
1758 Ok(None)
1759 }
1760
1761 fn find_case_split_candidates(
1767 &self,
1768 context: &[ProofExpr],
1769 skolem_constants: &[String],
1770 ) -> Vec<ProofExpr> {
1771 let mut candidates = Vec::new();
1772
1773 for expr in context {
1775 if let ProofExpr::Predicate { name, args, world } = expr {
1776 if args.len() == 2 {
1778 if let (ProofTerm::Constant(c1), ProofTerm::Constant(c2)) = (&args[0], &args[1]) {
1779 if c1 == c2 && skolem_constants.contains(c1) {
1780 candidates.push(expr.clone());
1781 }
1782 }
1783 }
1784 }
1785 }
1786
1787 let implications: Vec<(ProofExpr, ProofExpr)> = context.iter()
1790 .chain(self.knowledge_base.iter())
1791 .filter_map(|e| {
1792 if let ProofExpr::Implies(ante, cons) = e {
1793 Some(((**ante).clone(), (**cons).clone()))
1794 } else {
1795 None
1796 }
1797 })
1798 .collect();
1799
1800 for (ante, cons) in &implications {
1801 if let ProofExpr::Not(inner) = cons {
1803 if exprs_structurally_equal(ante, inner) {
1804 let neg_ante = ProofExpr::Not(Box::new(ante.clone()));
1806 for (a2, c2) in &implications {
1807 if exprs_structurally_equal(a2, &neg_ante) && exprs_structurally_equal(c2, ante) {
1808 if !candidates.contains(ante) {
1810 candidates.push(ante.clone());
1811 }
1812 }
1813 }
1814 }
1815 }
1816 }
1817
1818 for const_name in skolem_constants {
1821 for expr in context.iter().chain(self.knowledge_base.iter()) {
1823 if let ProofExpr::Implies(ante, cons) = expr {
1824 self.extract_predicate_template(cons, const_name, &mut candidates);
1826 }
1827 }
1828 }
1829
1830 candidates
1831 }
1832
1833 fn extract_predicate_template(
1835 &self,
1836 expr: &ProofExpr,
1837 skolem: &str,
1838 candidates: &mut Vec<ProofExpr>,
1839 ) {
1840 match expr {
1841 ProofExpr::Predicate { name, args, world } if args.len() == 2 => {
1842 let self_ref = ProofExpr::Predicate {
1844 name: name.clone(),
1845 args: vec![
1846 ProofTerm::Constant(skolem.to_string()),
1847 ProofTerm::Constant(skolem.to_string()),
1848 ],
1849 world: world.clone(),
1850 };
1851 if !candidates.contains(&self_ref) {
1852 candidates.push(self_ref);
1853 }
1854 }
1855 ProofExpr::Not(inner) => {
1856 self.extract_predicate_template(inner, skolem, candidates);
1857 }
1858 ProofExpr::NeoEvent { verb, .. } => {
1859 let self_ref = ProofExpr::Predicate {
1861 name: verb.to_lowercase(),
1862 args: vec![
1863 ProofTerm::Constant(skolem.to_string()),
1864 ProofTerm::Constant(skolem.to_string()),
1865 ],
1866 world: None,
1867 };
1868 if !candidates.contains(&self_ref) {
1869 candidates.push(self_ref);
1870 }
1871 }
1872 _ => {}
1873 }
1874 }
1875
1876 fn try_existential_elimination(
1888 &mut self,
1889 goal: &ProofGoal,
1890 depth: usize,
1891 ) -> ProofResult<Option<DerivationTree>> {
1892 if depth > 8 {
1894 return Ok(None);
1895 }
1896
1897 let existentials: Vec<ProofExpr> = self.knowledge_base.iter()
1899 .chain(goal.context.iter())
1900 .filter(|e| matches!(e, ProofExpr::Exists { .. }))
1901 .cloned()
1902 .collect();
1903
1904 if existentials.is_empty() {
1905 return Ok(None);
1906 }
1907
1908 for exist_expr in existentials {
1910 let witness_facts = self.skolemize_existential(&exist_expr);
1912
1913 if witness_facts.is_empty() {
1914 continue;
1915 }
1916
1917 let abstracted_facts: Vec<ProofExpr> = witness_facts.iter()
1919 .map(|f| self.abstract_all_events(f))
1920 .collect();
1921
1922 let mut extended_context = goal.context.clone();
1924 for fact in &abstracted_facts {
1925 if !extended_context.contains(fact) {
1926 extended_context.push(fact.clone());
1927 }
1928 }
1929
1930 for fact in &witness_facts {
1932 if !extended_context.contains(fact) {
1933 extended_context.push(fact.clone());
1934 }
1935 }
1936
1937 let extended_goal = ProofGoal::with_context(goal.target.clone(), extended_context);
1939
1940 if let Ok(inner_proof) = self.prove_goal(extended_goal, depth + 1) {
1943 let witness_name = if let ProofExpr::Exists { variable, .. } = &exist_expr {
1945 variable.clone()
1946 } else {
1947 "witness".to_string()
1948 };
1949
1950 return Ok(Some(DerivationTree::new(
1951 goal.target.clone(),
1952 InferenceRule::ExistentialElim { witness: witness_name },
1953 vec![inner_proof],
1954 )));
1955 }
1956 }
1957
1958 Ok(None)
1959 }
1960
1961 fn contains_quantifier(&self, expr: &ProofExpr) -> bool {
1963 match expr {
1964 ProofExpr::ForAll { .. } | ProofExpr::Exists { .. } => true,
1965 ProofExpr::And(l, r)
1966 | ProofExpr::Or(l, r)
1967 | ProofExpr::Implies(l, r)
1968 | ProofExpr::Iff(l, r) => self.contains_quantifier(l) || self.contains_quantifier(r),
1969 ProofExpr::Not(inner) => self.contains_quantifier(inner),
1970 _ => false,
1971 }
1972 }
1973
1974 fn skolemize_existential(&mut self, expr: &ProofExpr) -> Vec<ProofExpr> {
1980 let mut results = Vec::new();
1981
1982 if let ProofExpr::Exists { variable, body } = expr {
1983 let skolem = format!("sk_{}", self.fresh_var());
1985
1986 let mut subst = Substitution::new();
1988 subst.insert(variable.clone(), ProofTerm::Constant(skolem.clone()));
1989
1990 let instantiated = apply_subst_to_expr(body, &subst);
1991
1992 self.flatten_conjunction(&instantiated, &mut results);
1994
1995 let mut i = 0;
1997 while i < results.len() {
1998 if let ProofExpr::Exists { .. } = &results[i] {
1999 let nested = results.remove(i);
2000 let nested_skolem = self.skolemize_existential(&nested);
2001 results.extend(nested_skolem);
2002 } else {
2003 i += 1;
2004 }
2005 }
2006 }
2007
2008 results
2009 }
2010
2011 fn flatten_conjunction(&self, expr: &ProofExpr, results: &mut Vec<ProofExpr>) {
2013 match expr {
2014 ProofExpr::And(left, right) => {
2015 self.flatten_conjunction(left, results);
2016 self.flatten_conjunction(right, results);
2017 }
2018 other => results.push(other.clone()),
2019 }
2020 }
2021
2022 fn is_tautological_identity(&self, expr: &ProofExpr) -> bool {
2029 if let ProofExpr::Predicate { name, args, .. } = expr {
2030 args.len() == 1 && matches!(
2031 &args[0],
2032 ProofTerm::Constant(c) | ProofTerm::BoundVarRef(c) | ProofTerm::Variable(c) if c == name
2033 )
2034 } else {
2035 false
2036 }
2037 }
2038
2039 fn simplify_definite_description_conjunction(&self, expr: &ProofExpr) -> ProofExpr {
2042 match expr {
2043 ProofExpr::And(left, right) => {
2044 let left_simplified = self.simplify_definite_description_conjunction(left);
2046 let right_simplified = self.simplify_definite_description_conjunction(right);
2047
2048 if self.is_tautological_identity(&left_simplified) {
2050 return right_simplified;
2051 }
2052 if self.is_tautological_identity(&right_simplified) {
2053 return left_simplified;
2054 }
2055
2056 ProofExpr::And(
2057 Box::new(left_simplified),
2058 Box::new(right_simplified),
2059 )
2060 }
2061 ProofExpr::Or(left, right) => ProofExpr::Or(
2062 Box::new(self.simplify_definite_description_conjunction(left)),
2063 Box::new(self.simplify_definite_description_conjunction(right)),
2064 ),
2065 ProofExpr::Implies(left, right) => ProofExpr::Implies(
2066 Box::new(self.simplify_definite_description_conjunction(left)),
2067 Box::new(self.simplify_definite_description_conjunction(right)),
2068 ),
2069 ProofExpr::Iff(left, right) => ProofExpr::Iff(
2070 Box::new(self.simplify_definite_description_conjunction(left)),
2071 Box::new(self.simplify_definite_description_conjunction(right)),
2072 ),
2073 ProofExpr::Not(inner) => ProofExpr::Not(
2074 Box::new(self.simplify_definite_description_conjunction(inner)),
2075 ),
2076 ProofExpr::ForAll { variable, body } => ProofExpr::ForAll {
2077 variable: variable.clone(),
2078 body: Box::new(self.simplify_definite_description_conjunction(body)),
2079 },
2080 ProofExpr::Exists { variable, body } => ProofExpr::Exists {
2081 variable: variable.clone(),
2082 body: Box::new(self.simplify_definite_description_conjunction(body)),
2083 },
2084 ProofExpr::Temporal { operator, body } => ProofExpr::Temporal {
2085 operator: operator.clone(),
2086 body: Box::new(self.simplify_definite_description_conjunction(body)),
2087 },
2088 ProofExpr::TemporalBinary { operator, left, right } => ProofExpr::TemporalBinary {
2089 operator: operator.clone(),
2090 left: Box::new(self.simplify_definite_description_conjunction(left)),
2091 right: Box::new(self.simplify_definite_description_conjunction(right)),
2092 },
2093 _ => expr.clone(),
2094 }
2095 }
2096
2097 fn abstract_event_to_predicate(&self, expr: &ProofExpr) -> Option<ProofExpr> {
2108 match expr {
2109 ProofExpr::NeoEvent { verb, roles, .. } => {
2111 let agent = roles.iter()
2113 .find(|(role, _)| role == "Agent")
2114 .map(|(_, term)| term.clone());
2115
2116 let theme = roles.iter()
2117 .find(|(role, _)| role == "Theme" || role == "Patient")
2118 .map(|(_, term)| term.clone());
2119
2120 let mut args = Vec::new();
2122 if let Some(a) = agent {
2123 args.push(a);
2124 }
2125 if let Some(t) = theme {
2126 args.push(t);
2127 }
2128
2129 let pred_name = verb.to_lowercase();
2131
2132 Some(ProofExpr::Predicate {
2133 name: pred_name,
2134 args,
2135 world: None,
2136 })
2137 }
2138
2139 ProofExpr::Exists { variable, body } => {
2141 if !self.is_event_variable(variable) {
2143 return None;
2144 }
2145
2146 if let Some(abstracted) = self.abstract_event_to_predicate(body) {
2148 return Some(abstracted);
2149 }
2150
2151 if let Some(abstracted) = self.abstract_event_conjunction(variable, body) {
2154 return Some(abstracted);
2155 }
2156
2157 None
2158 }
2159
2160 _ => None,
2161 }
2162 }
2163
2164 fn abstract_event_conjunction(&self, event_var: &str, body: &ProofExpr) -> Option<ProofExpr> {
2168 let mut components = Vec::new();
2170 self.flatten_conjunction(body, &mut components);
2171
2172 let mut verb_name: Option<String> = None;
2174 let mut agent: Option<ProofTerm> = None;
2175 let mut theme: Option<ProofTerm> = None;
2176
2177 for comp in &components {
2178 if let ProofExpr::Predicate { name, args, .. } = comp {
2179 let first_is_event = args.first().map_or(false, |arg| {
2181 matches!(arg, ProofTerm::Variable(v) | ProofTerm::BoundVarRef(v) if v == event_var)
2182 });
2183
2184 if !first_is_event && args.len() == 1 {
2185 if let Some(ProofTerm::Variable(v) | ProofTerm::BoundVarRef(v)) = args.first() {
2187 if v == event_var {
2188 verb_name = Some(name.clone());
2189 continue;
2190 }
2191 }
2192 }
2193
2194 if first_is_event {
2195 match name.as_str() {
2196 "Agent" if args.len() == 2 => {
2197 agent = Some(args[1].clone());
2198 }
2199 "Theme" | "Patient" if args.len() == 2 => {
2200 theme = Some(args[1].clone());
2201 }
2202 _ if args.len() == 1 && verb_name.is_none() => {
2203 verb_name = Some(name.clone());
2205 }
2206 _ => {}
2207 }
2208 }
2209 }
2210 }
2211
2212 if let Some(verb) = verb_name {
2214 let mut args = Vec::new();
2215 if let Some(a) = agent {
2216 args.push(a);
2217 }
2218 if let Some(t) = theme {
2219 args.push(t);
2220 }
2221
2222 return Some(ProofExpr::Predicate {
2223 name: verb.to_lowercase(),
2224 args,
2225 world: None,
2226 });
2227 }
2228
2229 None
2230 }
2231
2232 fn is_event_variable(&self, var: &str) -> bool {
2236 var == "e" || var.starts_with("e_") ||
2237 (var.starts_with('e') && var.len() == 2 && var.chars().nth(1).map_or(false, |c| c.is_ascii_digit()))
2238 }
2239
2240 fn abstract_all_events(&self, expr: &ProofExpr) -> ProofExpr {
2245 if let Some(abstracted) = self.abstract_event_to_predicate(expr) {
2247 return abstracted;
2248 }
2249
2250 match expr {
2252 ProofExpr::And(left, right) => ProofExpr::And(
2253 Box::new(self.abstract_all_events(left)),
2254 Box::new(self.abstract_all_events(right)),
2255 ),
2256 ProofExpr::Or(left, right) => ProofExpr::Or(
2257 Box::new(self.abstract_all_events(left)),
2258 Box::new(self.abstract_all_events(right)),
2259 ),
2260 ProofExpr::Implies(left, right) => ProofExpr::Implies(
2261 Box::new(self.abstract_all_events(left)),
2262 Box::new(self.abstract_all_events(right)),
2263 ),
2264 ProofExpr::Iff(left, right) => ProofExpr::Iff(
2265 Box::new(self.abstract_all_events(left)),
2266 Box::new(self.abstract_all_events(right)),
2267 ),
2268 ProofExpr::Not(inner) => {
2269 if let ProofExpr::Exists { variable, body } = inner.as_ref() {
2273 return ProofExpr::ForAll {
2274 variable: variable.clone(),
2275 body: Box::new(self.abstract_all_events(&ProofExpr::Not(body.clone()))),
2276 };
2277 }
2278 ProofExpr::Not(Box::new(self.abstract_all_events(inner)))
2281 }
2282 ProofExpr::ForAll { variable, body } => {
2283 if let ProofExpr::Not(inner) = body.as_ref() {
2286 if let ProofExpr::And(left, right) = inner.as_ref() {
2287 return ProofExpr::ForAll {
2288 variable: variable.clone(),
2289 body: Box::new(ProofExpr::Implies(
2290 Box::new(self.abstract_all_events(left)),
2291 Box::new(self.abstract_all_events(&ProofExpr::Not(right.clone()))),
2292 )),
2293 };
2294 }
2295 }
2296 ProofExpr::ForAll {
2297 variable: variable.clone(),
2298 body: Box::new(self.abstract_all_events(body)),
2299 }
2300 }
2301 ProofExpr::Exists { variable, body } => {
2302 if self.is_event_variable(variable) {
2304 if let Some(abstracted) = self.abstract_event_to_predicate(body) {
2305 return abstracted;
2306 }
2307 }
2308 ProofExpr::Exists {
2310 variable: variable.clone(),
2311 body: Box::new(self.abstract_all_events(body)),
2312 }
2313 }
2314 other => other.clone(),
2316 }
2317 }
2318
2319 fn abstract_events_only(&self, expr: &ProofExpr) -> ProofExpr {
2324 if let Some(abstracted) = self.abstract_event_to_predicate(expr) {
2326 return abstracted;
2327 }
2328
2329 match expr {
2331 ProofExpr::And(left, right) => ProofExpr::And(
2332 Box::new(self.abstract_events_only(left)),
2333 Box::new(self.abstract_events_only(right)),
2334 ),
2335 ProofExpr::Or(left, right) => ProofExpr::Or(
2336 Box::new(self.abstract_events_only(left)),
2337 Box::new(self.abstract_events_only(right)),
2338 ),
2339 ProofExpr::Implies(left, right) => ProofExpr::Implies(
2340 Box::new(self.abstract_events_only(left)),
2341 Box::new(self.abstract_events_only(right)),
2342 ),
2343 ProofExpr::Iff(left, right) => ProofExpr::Iff(
2344 Box::new(self.abstract_events_only(left)),
2345 Box::new(self.abstract_events_only(right)),
2346 ),
2347 ProofExpr::Not(inner) => {
2348 ProofExpr::Not(Box::new(self.abstract_events_only(inner)))
2350 }
2351 ProofExpr::ForAll { variable, body } => ProofExpr::ForAll {
2352 variable: variable.clone(),
2353 body: Box::new(self.abstract_events_only(body)),
2354 },
2355 ProofExpr::Exists { variable, body } => {
2356 if self.is_event_variable(variable) {
2358 if let Some(abstracted) = self.abstract_event_to_predicate(body) {
2359 return abstracted;
2360 }
2361 }
2362 ProofExpr::Exists {
2364 variable: variable.clone(),
2365 body: Box::new(self.abstract_events_only(body)),
2366 }
2367 }
2368 other => other.clone(),
2370 }
2371 }
2372
2373 fn find_contradiction(
2377 &mut self,
2378 context: &[ProofExpr],
2379 depth: usize,
2380 ) -> ProofResult<Option<DerivationTree>> {
2381 let all_exprs: Vec<ProofExpr> = self.knowledge_base.iter()
2383 .chain(context.iter())
2384 .cloned()
2385 .collect();
2386
2387 for expr in &all_exprs {
2389 if let ProofExpr::Not(inner) = expr {
2390 for other in &all_exprs {
2392 if exprs_structurally_equal(other, inner) {
2393 let pos_leaf = DerivationTree::leaf(
2395 (**inner).clone(),
2396 InferenceRule::PremiseMatch,
2397 );
2398 let neg_leaf = DerivationTree::leaf(
2399 expr.clone(),
2400 InferenceRule::PremiseMatch,
2401 );
2402 return Ok(Some(DerivationTree::new(
2403 ProofExpr::Atom("⊥".into()),
2404 InferenceRule::Contradiction,
2405 vec![pos_leaf, neg_leaf],
2406 )));
2407 }
2408 }
2409 }
2410 }
2411
2412 let mut implications: Vec<(ProofExpr, ProofExpr)> = Vec::new();
2417 for e in &all_exprs {
2418 if let ProofExpr::Implies(ante, cons) = e {
2419 implications.push(((**ante).clone(), (**cons).clone()));
2420 }
2421 if let ProofExpr::ForAll { body, .. } = e {
2423 if let ProofExpr::Implies(ante, cons) = body.as_ref() {
2424 implications.push(((**ante).clone(), (**cons).clone()));
2425 }
2426 }
2427 }
2428
2429 for fact in context {
2431 let mut derivable_consequences: Vec<ProofExpr> = Vec::new();
2433
2434 for (ante, cons) in &implications {
2435 if let Ok(subst) = unify_exprs(fact, ante) {
2437 let instantiated_cons = apply_subst_to_expr(cons, &subst);
2438 derivable_consequences.push(instantiated_cons);
2439 }
2440
2441 if let ProofExpr::And(left, right) = ante {
2443 if let Some(subst) = self.try_match_conjunction_antecedent(
2445 left, right, &all_exprs
2446 ) {
2447 let instantiated_cons = apply_subst_to_expr(cons, &subst);
2448 if !derivable_consequences.contains(&instantiated_cons) {
2449 derivable_consequences.push(instantiated_cons);
2450 }
2451 }
2452 }
2453 }
2454
2455 for cons in &derivable_consequences {
2457 if let ProofExpr::Not(inner) = cons {
2459 if exprs_structurally_equal(inner, fact) {
2460 let pos_leaf = DerivationTree::leaf(
2463 fact.clone(),
2464 InferenceRule::PremiseMatch,
2465 );
2466 let neg_leaf = DerivationTree::leaf(
2467 cons.clone(),
2468 InferenceRule::ModusPonens,
2469 );
2470 return Ok(Some(DerivationTree::new(
2471 ProofExpr::Atom("⊥".into()),
2472 InferenceRule::Contradiction,
2473 vec![pos_leaf, neg_leaf],
2474 )));
2475 }
2476 }
2477
2478 for other in context {
2480 if std::ptr::eq(fact as *const _, other as *const _) {
2481 continue; }
2483 if let ProofExpr::Not(inner) = cons {
2485 if exprs_structurally_equal(inner, other) {
2486 let pos_leaf = DerivationTree::leaf(
2487 other.clone(),
2488 InferenceRule::PremiseMatch,
2489 );
2490 let neg_leaf = DerivationTree::leaf(
2491 cons.clone(),
2492 InferenceRule::ModusPonens,
2493 );
2494 return Ok(Some(DerivationTree::new(
2495 ProofExpr::Atom("⊥".into()),
2496 InferenceRule::Contradiction,
2497 vec![pos_leaf, neg_leaf],
2498 )));
2499 }
2500 }
2501 if let ProofExpr::Not(inner_other) = other {
2503 if exprs_structurally_equal(inner_other, cons) {
2504 let pos_leaf = DerivationTree::leaf(
2505 cons.clone(),
2506 InferenceRule::ModusPonens,
2507 );
2508 let neg_leaf = DerivationTree::leaf(
2509 other.clone(),
2510 InferenceRule::PremiseMatch,
2511 );
2512 return Ok(Some(DerivationTree::new(
2513 ProofExpr::Atom("⊥".into()),
2514 InferenceRule::Contradiction,
2515 vec![pos_leaf, neg_leaf],
2516 )));
2517 }
2518 }
2519 }
2520 }
2521
2522 for i in 0..derivable_consequences.len() {
2524 for j in (i + 1)..derivable_consequences.len() {
2525 let cons1 = &derivable_consequences[i];
2526 let cons2 = &derivable_consequences[j];
2527
2528 if let ProofExpr::Not(inner1) = cons1 {
2530 if exprs_structurally_equal(inner1, cons2) {
2531 let pos_leaf = DerivationTree::leaf(
2533 cons2.clone(),
2534 InferenceRule::ModusPonens,
2535 );
2536 let neg_leaf = DerivationTree::leaf(
2537 cons1.clone(),
2538 InferenceRule::ModusPonens,
2539 );
2540 return Ok(Some(DerivationTree::new(
2541 ProofExpr::Atom("⊥".into()),
2542 InferenceRule::Contradiction,
2543 vec![pos_leaf, neg_leaf],
2544 )));
2545 }
2546 }
2547 if let ProofExpr::Not(inner2) = cons2 {
2548 if exprs_structurally_equal(inner2, cons1) {
2549 let pos_leaf = DerivationTree::leaf(
2551 cons1.clone(),
2552 InferenceRule::ModusPonens,
2553 );
2554 let neg_leaf = DerivationTree::leaf(
2555 cons2.clone(),
2556 InferenceRule::ModusPonens,
2557 );
2558 return Ok(Some(DerivationTree::new(
2559 ProofExpr::Atom("⊥".into()),
2560 InferenceRule::Contradiction,
2561 vec![pos_leaf, neg_leaf],
2562 )));
2563 }
2564 }
2565 }
2566 }
2567 }
2568
2569 if let Some(proof) = self.find_self_referential_contradiction(context, depth)? {
2571 return Ok(Some(proof));
2572 }
2573
2574 Ok(None)
2575 }
2576
2577 fn try_match_conjunction_antecedent(
2582 &self,
2583 left: &ProofExpr,
2584 right: &ProofExpr,
2585 facts: &[ProofExpr],
2586 ) -> Option<Substitution> {
2587 for fact1 in facts {
2589 if let Ok(subst1) = unify_exprs(fact1, left) {
2590 let instantiated_right = apply_subst_to_expr(right, &subst1);
2592 for fact2 in facts {
2594 if let Ok(subst2) = unify_exprs(fact2, &instantiated_right) {
2595 let mut combined = subst1.clone();
2597 for (k, v) in subst2.iter() {
2598 combined.insert(k.clone(), v.clone());
2599 }
2600 return Some(combined);
2601 }
2602 }
2603 }
2604 }
2605 for fact1 in facts {
2607 if let Ok(subst1) = unify_exprs(fact1, right) {
2608 let instantiated_left = apply_subst_to_expr(left, &subst1);
2609 for fact2 in facts {
2610 if let Ok(subst2) = unify_exprs(fact2, &instantiated_left) {
2611 let mut combined = subst1.clone();
2612 for (k, v) in subst2.iter() {
2613 combined.insert(k.clone(), v.clone());
2614 }
2615 return Some(combined);
2616 }
2617 }
2618 }
2619 }
2620 None
2621 }
2622
2623 fn find_self_referential_contradiction(
2631 &mut self,
2632 context: &[ProofExpr],
2633 _depth: usize,
2634 ) -> ProofResult<Option<DerivationTree>> {
2635 let all_exprs: Vec<ProofExpr> = self.knowledge_base.iter()
2637 .chain(context.iter())
2638 .cloned()
2639 .collect();
2640
2641 for expr1 in &all_exprs {
2644 if let ProofExpr::ForAll { variable: var1, body: body1 } = expr1 {
2645 if let ProofExpr::Implies(ante1, cons1) = body1.as_ref() {
2646 for expr2 in &all_exprs {
2647 if std::ptr::eq(expr1, expr2) {
2648 continue; }
2650 if let ProofExpr::ForAll { variable: var2, body: body2 } = expr2 {
2651 if let ProofExpr::Implies(ante2, cons2) = body2.as_ref() {
2652 if let ProofExpr::Not(neg_cons2) = cons2.as_ref() {
2654 let witnesses = self.extract_constants_from_expr(cons1);
2660
2661 for witness_name in &witnesses {
2662 let witness = ProofTerm::Constant(witness_name.clone());
2663
2664 let mut subst1 = Substitution::new();
2666 subst1.insert(var1.clone(), witness.clone());
2667 let ante1_inst = apply_subst_to_expr(ante1, &subst1);
2668 let cons1_inst = apply_subst_to_expr(cons1, &subst1);
2669
2670 let mut subst2 = Substitution::new();
2671 subst2.insert(var2.clone(), witness.clone());
2672 let ante2_inst = apply_subst_to_expr(ante2, &subst2);
2673 let cons2_inst = apply_subst_to_expr(cons2, &subst2);
2674
2675 if let ProofExpr::Not(inner2) = &cons2_inst {
2678 if exprs_structurally_equal(&cons1_inst, inner2) {
2679 if self.are_complements(&ante1_inst, &ante2_inst) {
2691 let pos_leaf = DerivationTree::leaf(
2695 cons1_inst.clone(),
2696 InferenceRule::ModusPonens,
2697 );
2698 let neg_leaf = DerivationTree::leaf(
2699 cons2_inst,
2700 InferenceRule::ModusPonens,
2701 );
2702 return Ok(Some(DerivationTree::new(
2703 ProofExpr::Atom("⊥".into()),
2704 InferenceRule::Contradiction,
2705 vec![pos_leaf, neg_leaf],
2706 )));
2707 }
2708 }
2709 }
2710 }
2711 }
2712 }
2713 }
2714 }
2715 }
2716 }
2717 }
2718
2719 Ok(None)
2720 }
2721
2722 fn are_complements(&self, expr1: &ProofExpr, expr2: &ProofExpr) -> bool {
2724 if let ProofExpr::Not(inner1) = expr1 {
2726 if exprs_structurally_equal(inner1, expr2) {
2727 return true;
2728 }
2729 }
2730 if let ProofExpr::Not(inner2) = expr2 {
2732 if exprs_structurally_equal(inner2, expr1) {
2733 return true;
2734 }
2735 }
2736 false
2737 }
2738
2739 fn extract_constants_from_expr(&self, expr: &ProofExpr) -> Vec<String> {
2741 let mut constants = Vec::new();
2742 self.extract_constants_recursive(expr, &mut constants);
2743 constants
2744 }
2745
2746 fn extract_constants_recursive(&self, expr: &ProofExpr, constants: &mut Vec<String>) {
2747 match expr {
2748 ProofExpr::Predicate { args, .. } => {
2749 for arg in args {
2750 self.extract_constants_from_term_recursive(arg, constants);
2751 }
2752 }
2753 ProofExpr::Identity(l, r) => {
2754 self.extract_constants_from_term_recursive(l, constants);
2755 self.extract_constants_from_term_recursive(r, constants);
2756 }
2757 ProofExpr::And(l, r)
2758 | ProofExpr::Or(l, r)
2759 | ProofExpr::Implies(l, r)
2760 | ProofExpr::Iff(l, r) => {
2761 self.extract_constants_recursive(l, constants);
2762 self.extract_constants_recursive(r, constants);
2763 }
2764 ProofExpr::Not(inner) => {
2765 self.extract_constants_recursive(inner, constants);
2766 }
2767 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
2768 self.extract_constants_recursive(body, constants);
2769 }
2770 _ => {}
2771 }
2772 }
2773
2774 fn extract_constants_from_term_recursive(&self, term: &ProofTerm, constants: &mut Vec<String>) {
2775 match term {
2776 ProofTerm::Constant(name) => {
2777 if !constants.contains(name) {
2778 constants.push(name.clone());
2779 }
2780 }
2781 ProofTerm::Function(_, args) => {
2782 for arg in args {
2783 self.extract_constants_from_term_recursive(arg, constants);
2784 }
2785 }
2786 ProofTerm::Group(terms) => {
2787 for t in terms {
2788 self.extract_constants_from_term_recursive(t, constants);
2789 }
2790 }
2791 _ => {}
2792 }
2793 }
2794
2795 fn try_equality_rewrite(
2804 &mut self,
2805 goal: &ProofGoal,
2806 depth: usize,
2807 ) -> ProofResult<Option<DerivationTree>> {
2808 let equalities: Vec<(ProofTerm, ProofTerm)> = self
2810 .knowledge_base
2811 .iter()
2812 .chain(goal.context.iter())
2813 .filter_map(|expr| {
2814 if let ProofExpr::Identity(l, r) = expr {
2815 Some((l.clone(), r.clone()))
2816 } else {
2817 None
2818 }
2819 })
2820 .collect();
2821
2822 if equalities.is_empty() {
2823 return Ok(None);
2824 }
2825
2826 if let ProofExpr::Identity(goal_l, goal_r) = &goal.target {
2828 if let Some(tree) = self.try_equality_symmetry(goal_l, goal_r, &equalities, depth)? {
2830 return Ok(Some(tree));
2831 }
2832
2833 if let Some(tree) = self.try_equality_transitivity(goal_l, goal_r, &equalities, depth)? {
2835 return Ok(Some(tree));
2836 }
2837
2838 if depth + 3 < self.max_depth {
2841 if let Some(tree) = self.try_equational_identity_rewrite(goal, goal_l, goal_r, depth)? {
2842 return Ok(Some(tree));
2843 }
2844 }
2845
2846 return Ok(None);
2847 }
2848
2849 for (eq_from, eq_to) in &equalities {
2851 if let Some(tree) = self.try_rewrite_with_equality(
2853 goal, eq_from, eq_to, depth,
2854 )? {
2855 return Ok(Some(tree));
2856 }
2857
2858 if let Some(tree) = self.try_rewrite_with_equality(
2860 goal, eq_to, eq_from, depth,
2861 )? {
2862 return Ok(Some(tree));
2863 }
2864 }
2865
2866 Ok(None)
2867 }
2868
2869 fn try_rewrite_with_equality(
2871 &mut self,
2872 goal: &ProofGoal,
2873 from: &ProofTerm,
2874 to: &ProofTerm,
2875 depth: usize,
2876 ) -> ProofResult<Option<DerivationTree>> {
2877 let source_goal = self.substitute_term_in_expr(&goal.target, to, from);
2880
2881 if source_goal == goal.target {
2883 return Ok(None);
2884 }
2885
2886 let source_proof_goal = ProofGoal::with_context(source_goal.clone(), goal.context.clone());
2888 if let Ok(source_proof) = self.prove_goal(source_proof_goal, depth + 1) {
2889 let equality = ProofExpr::Identity(from.clone(), to.clone());
2891 let eq_proof_goal = ProofGoal::with_context(equality.clone(), goal.context.clone());
2892
2893 if let Ok(eq_proof) = self.prove_goal(eq_proof_goal, depth + 1) {
2894 return Ok(Some(DerivationTree::new(
2895 goal.target.clone(),
2896 InferenceRule::Rewrite {
2897 from: from.clone(),
2898 to: to.clone(),
2899 },
2900 vec![eq_proof, source_proof],
2901 )));
2902 }
2903 }
2904
2905 Ok(None)
2906 }
2907
2908 fn try_equality_symmetry(
2910 &mut self,
2911 goal_l: &ProofTerm,
2912 goal_r: &ProofTerm,
2913 equalities: &[(ProofTerm, ProofTerm)],
2914 _depth: usize,
2915 ) -> ProofResult<Option<DerivationTree>> {
2916 for (eq_l, eq_r) in equalities {
2918 if eq_l == goal_r && eq_r == goal_l {
2919 let source = ProofExpr::Identity(goal_r.clone(), goal_l.clone());
2921 return Ok(Some(DerivationTree::new(
2922 ProofExpr::Identity(goal_l.clone(), goal_r.clone()),
2923 InferenceRule::EqualitySymmetry,
2924 vec![DerivationTree::leaf(source, InferenceRule::PremiseMatch)],
2925 )));
2926 }
2927 }
2928 Ok(None)
2929 }
2930
2931 fn try_equality_transitivity(
2933 &mut self,
2934 goal_l: &ProofTerm,
2935 goal_r: &ProofTerm,
2936 equalities: &[(ProofTerm, ProofTerm)],
2937 _depth: usize,
2938 ) -> ProofResult<Option<DerivationTree>> {
2939 for (eq1_l, eq1_r) in equalities {
2941 if eq1_l == goal_l {
2942 for (eq2_l, eq2_r) in equalities {
2944 if eq2_l == eq1_r && eq2_r == goal_r {
2945 let premise1 = ProofExpr::Identity(eq1_l.clone(), eq1_r.clone());
2947 let premise2 = ProofExpr::Identity(eq2_l.clone(), eq2_r.clone());
2948 return Ok(Some(DerivationTree::new(
2949 ProofExpr::Identity(goal_l.clone(), goal_r.clone()),
2950 InferenceRule::EqualityTransitivity,
2951 vec![
2952 DerivationTree::leaf(premise1, InferenceRule::PremiseMatch),
2953 DerivationTree::leaf(premise2, InferenceRule::PremiseMatch),
2954 ],
2955 )));
2956 }
2957 }
2958 }
2959 }
2960 Ok(None)
2961 }
2962
2963 fn try_equational_identity_rewrite(
2968 &mut self,
2969 goal: &ProofGoal,
2970 goal_l: &ProofTerm,
2971 goal_r: &ProofTerm,
2972 depth: usize,
2973 ) -> ProofResult<Option<DerivationTree>> {
2974 if let (
2977 ProofTerm::Function(name_l, args_l),
2978 ProofTerm::Function(name_r, args_r),
2979 ) = (goal_l, goal_r)
2980 {
2981 if name_l == name_r && args_l.len() == args_r.len() {
2982 let mut arg_proofs = Vec::new();
2984 let mut all_ok = true;
2985 for (arg_l, arg_r) in args_l.iter().zip(args_r.iter()) {
2986 let arg_goal_expr = ProofExpr::Identity(arg_l.clone(), arg_r.clone());
2987 let arg_goal = ProofGoal::with_context(arg_goal_expr, goal.context.clone());
2988 match self.prove_goal(arg_goal, depth + 1) {
2989 Ok(proof) => arg_proofs.push(proof),
2990 Err(_) => {
2991 all_ok = false;
2992 break;
2993 }
2994 }
2995 }
2996 if all_ok {
2997 return Ok(Some(DerivationTree::new(
2999 goal.target.clone(),
3000 InferenceRule::Reflexivity, arg_proofs,
3002 )));
3003 }
3004 }
3005 }
3006 let axioms: Vec<(ProofTerm, ProofTerm)> = self
3008 .knowledge_base
3009 .iter()
3010 .filter_map(|e| {
3011 if let ProofExpr::Identity(l, r) = e {
3012 Some((l.clone(), r.clone()))
3013 } else {
3014 None
3015 }
3016 })
3017 .collect();
3018
3019 for (axiom_l, axiom_r) in &axioms {
3021 let mut var_map = std::collections::HashMap::new();
3023 let renamed_l = self.rename_term_vars_with_map(axiom_l, &mut var_map);
3024 let renamed_r = self.rename_term_vars_with_map(axiom_r, &mut var_map);
3025
3026 if let Ok(subst) = unify_terms(&renamed_l, goal_l) {
3030 let rewritten = self.apply_subst_to_term(&renamed_r, &subst);
3032
3033 if terms_structurally_equal(&rewritten, goal_r) {
3035 let axiom_expr = ProofExpr::Identity(axiom_l.clone(), axiom_r.clone());
3037 return Ok(Some(DerivationTree::new(
3038 goal.target.clone(),
3039 InferenceRule::Rewrite {
3040 from: goal_l.clone(),
3041 to: rewritten,
3042 },
3043 vec![DerivationTree::leaf(axiom_expr, InferenceRule::PremiseMatch)],
3044 )));
3045 }
3046
3047 let new_goal_expr = ProofExpr::Identity(rewritten.clone(), goal_r.clone());
3049 let new_goal = ProofGoal::with_context(new_goal_expr.clone(), goal.context.clone());
3050
3051 if let Ok(sub_proof) = self.prove_goal(new_goal, depth + 1) {
3053 let axiom_expr = ProofExpr::Identity(axiom_l.clone(), axiom_r.clone());
3055 return Ok(Some(DerivationTree::new(
3056 goal.target.clone(),
3057 InferenceRule::Rewrite {
3058 from: goal_l.clone(),
3059 to: rewritten,
3060 },
3061 vec![
3062 DerivationTree::leaf(axiom_expr, InferenceRule::PremiseMatch),
3063 sub_proof,
3064 ],
3065 )));
3066 }
3067 }
3068 }
3069
3070 Ok(None)
3071 }
3072
3073 fn rename_term_vars(&mut self, term: &ProofTerm) -> ProofTerm {
3075 let mut var_map = std::collections::HashMap::new();
3076 self.rename_term_vars_with_map(term, &mut var_map)
3077 }
3078
3079 fn rename_term_vars_with_map(
3080 &mut self,
3081 term: &ProofTerm,
3082 var_map: &mut std::collections::HashMap<String, String>,
3083 ) -> ProofTerm {
3084 match term {
3085 ProofTerm::Variable(name) => {
3086 if let Some(fresh) = var_map.get(name) {
3088 ProofTerm::Variable(fresh.clone())
3089 } else {
3090 let fresh = format!("_v{}", self.var_counter);
3092 self.var_counter += 1;
3093 var_map.insert(name.clone(), fresh.clone());
3094 ProofTerm::Variable(fresh)
3095 }
3096 }
3097 ProofTerm::Function(name, args) => {
3098 ProofTerm::Function(
3099 name.clone(),
3100 args.iter().map(|a| self.rename_term_vars_with_map(a, var_map)).collect(),
3101 )
3102 }
3103 ProofTerm::Group(terms) => {
3104 ProofTerm::Group(
3105 terms.iter().map(|t| self.rename_term_vars_with_map(t, var_map)).collect(),
3106 )
3107 }
3108 other => other.clone(),
3109 }
3110 }
3111
3112 fn apply_subst_to_term(&self, term: &ProofTerm, subst: &Substitution) -> ProofTerm {
3114 match term {
3115 ProofTerm::Variable(name) => {
3116 if let Some(replacement) = subst.get(name) {
3117 replacement.clone()
3118 } else {
3119 term.clone()
3120 }
3121 }
3122 ProofTerm::Function(name, args) => {
3123 ProofTerm::Function(
3124 name.clone(),
3125 args.iter().map(|a| self.apply_subst_to_term(a, subst)).collect(),
3126 )
3127 }
3128 ProofTerm::Group(terms) => {
3129 ProofTerm::Group(terms.iter().map(|t| self.apply_subst_to_term(t, subst)).collect())
3130 }
3131 other => other.clone(),
3132 }
3133 }
3134
3135 fn substitute_term_in_expr(
3137 &self,
3138 expr: &ProofExpr,
3139 from: &ProofTerm,
3140 to: &ProofTerm,
3141 ) -> ProofExpr {
3142 match expr {
3143 ProofExpr::Predicate { name, args, world } => {
3144 let new_args: Vec<_> = args
3145 .iter()
3146 .map(|arg| self.substitute_in_term(arg, from, to))
3147 .collect();
3148 ProofExpr::Predicate {
3149 name: name.clone(),
3150 args: new_args,
3151 world: world.clone(),
3152 }
3153 }
3154 ProofExpr::Identity(l, r) => ProofExpr::Identity(
3155 self.substitute_in_term(l, from, to),
3156 self.substitute_in_term(r, from, to),
3157 ),
3158 ProofExpr::And(l, r) => ProofExpr::And(
3159 Box::new(self.substitute_term_in_expr(l, from, to)),
3160 Box::new(self.substitute_term_in_expr(r, from, to)),
3161 ),
3162 ProofExpr::Or(l, r) => ProofExpr::Or(
3163 Box::new(self.substitute_term_in_expr(l, from, to)),
3164 Box::new(self.substitute_term_in_expr(r, from, to)),
3165 ),
3166 ProofExpr::Implies(l, r) => ProofExpr::Implies(
3167 Box::new(self.substitute_term_in_expr(l, from, to)),
3168 Box::new(self.substitute_term_in_expr(r, from, to)),
3169 ),
3170 ProofExpr::Not(inner) => {
3171 ProofExpr::Not(Box::new(self.substitute_term_in_expr(inner, from, to)))
3172 }
3173 ProofExpr::ForAll { variable, body } => ProofExpr::ForAll {
3174 variable: variable.clone(),
3175 body: Box::new(self.substitute_term_in_expr(body, from, to)),
3176 },
3177 ProofExpr::Exists { variable, body } => ProofExpr::Exists {
3178 variable: variable.clone(),
3179 body: Box::new(self.substitute_term_in_expr(body, from, to)),
3180 },
3181 other => other.clone(),
3183 }
3184 }
3185
3186 fn substitute_in_term(
3188 &self,
3189 term: &ProofTerm,
3190 from: &ProofTerm,
3191 to: &ProofTerm,
3192 ) -> ProofTerm {
3193 if term == from {
3194 return to.clone();
3195 }
3196 match term {
3197 ProofTerm::Function(name, args) => {
3198 let new_args: Vec<_> = args
3199 .iter()
3200 .map(|arg| self.substitute_in_term(arg, from, to))
3201 .collect();
3202 ProofTerm::Function(name.clone(), new_args)
3203 }
3204 ProofTerm::Group(terms) => {
3205 let new_terms: Vec<_> = terms
3206 .iter()
3207 .map(|t| self.substitute_in_term(t, from, to))
3208 .collect();
3209 ProofTerm::Group(new_terms)
3210 }
3211 other => other.clone(),
3212 }
3213 }
3214
3215 fn try_structural_induction(
3229 &mut self,
3230 goal: &ProofGoal,
3231 depth: usize,
3232 ) -> ProofResult<Option<DerivationTree>> {
3233 if let Some((var_name, typename)) = self.find_typed_var(&goal.target) {
3235 if let Some(motive) = self.try_infer_motive(&goal.target, &var_name) {
3237 match typename.as_str() {
3238 "Nat" => {
3239 if let Ok(Some(proof)) =
3240 self.try_nat_induction_with_motive(goal, &var_name, &motive, depth)
3241 {
3242 return Ok(Some(proof));
3243 }
3244 }
3245 "List" => {
3246 }
3248 _ => {}
3249 }
3250 }
3251
3252 match typename.as_str() {
3254 "Nat" => self.try_nat_induction(goal, &var_name, depth),
3255 "List" => self.try_list_induction(goal, &var_name, depth),
3256 _ => Ok(None), }
3258 } else {
3259 Ok(None)
3260 }
3261 }
3262
3263 fn try_infer_motive(&self, goal: &ProofExpr, var_name: &str) -> Option<ProofExpr> {
3268 let motive_hole = ProofExpr::Hole("Motive".to_string());
3270 let pattern = ProofExpr::App(
3271 Box::new(motive_hole),
3272 Box::new(ProofExpr::Term(ProofTerm::BoundVarRef(var_name.to_string()))),
3273 );
3274
3275 let body = self.convert_typed_var_to_variable(goal, var_name);
3277
3278 match unify_pattern(&pattern, &body) {
3280 Ok(solution) => solution.get("Motive").cloned(),
3281 Err(_) => None,
3282 }
3283 }
3284
3285 fn convert_typed_var_to_variable(&self, expr: &ProofExpr, var_name: &str) -> ProofExpr {
3290 match expr {
3291 ProofExpr::TypedVar { name, .. } if name == var_name => {
3292 ProofExpr::Atom(name.clone())
3294 }
3295 ProofExpr::Identity(l, r) => ProofExpr::Identity(
3296 self.convert_typed_var_in_term(l, var_name),
3297 self.convert_typed_var_in_term(r, var_name),
3298 ),
3299 ProofExpr::Predicate { name, args, world } => ProofExpr::Predicate {
3300 name: name.clone(),
3301 args: args
3302 .iter()
3303 .map(|a| self.convert_typed_var_in_term(a, var_name))
3304 .collect(),
3305 world: world.clone(),
3306 },
3307 ProofExpr::And(l, r) => ProofExpr::And(
3308 Box::new(self.convert_typed_var_to_variable(l, var_name)),
3309 Box::new(self.convert_typed_var_to_variable(r, var_name)),
3310 ),
3311 ProofExpr::Or(l, r) => ProofExpr::Or(
3312 Box::new(self.convert_typed_var_to_variable(l, var_name)),
3313 Box::new(self.convert_typed_var_to_variable(r, var_name)),
3314 ),
3315 ProofExpr::Not(inner) => {
3316 ProofExpr::Not(Box::new(self.convert_typed_var_to_variable(inner, var_name)))
3317 }
3318 _ => expr.clone(),
3319 }
3320 }
3321
3322 fn convert_typed_var_in_term(&self, term: &ProofTerm, var_name: &str) -> ProofTerm {
3324 match term {
3325 ProofTerm::Variable(v) => {
3326 if v == var_name || v.starts_with(&format!("{}:", var_name)) {
3328 ProofTerm::Variable(var_name.to_string())
3329 } else {
3330 term.clone()
3331 }
3332 }
3333 ProofTerm::Function(name, args) => ProofTerm::Function(
3334 name.clone(),
3335 args.iter()
3336 .map(|a| self.convert_typed_var_in_term(a, var_name))
3337 .collect(),
3338 ),
3339 ProofTerm::Group(terms) => ProofTerm::Group(
3340 terms
3341 .iter()
3342 .map(|t| self.convert_typed_var_in_term(t, var_name))
3343 .collect(),
3344 ),
3345 _ => term.clone(),
3346 }
3347 }
3348
3349 fn try_nat_induction_with_motive(
3357 &mut self,
3358 goal: &ProofGoal,
3359 var_name: &str,
3360 motive: &ProofExpr,
3361 depth: usize,
3362 ) -> ProofResult<Option<DerivationTree>> {
3363 let zero_ctor = ProofExpr::Ctor {
3366 name: "Zero".into(),
3367 args: vec![],
3368 };
3369 let base_goal_expr = beta_reduce(&ProofExpr::App(
3370 Box::new(motive.clone()),
3371 Box::new(zero_ctor),
3372 ));
3373
3374 let base_goal = ProofGoal::with_context(base_goal_expr, goal.context.clone());
3375 let base_proof = match self.prove_goal(base_goal, depth + 1) {
3376 Ok(proof) => proof,
3377 Err(_) => return Ok(None),
3378 };
3379
3380 let fresh_k = self.fresh_var();
3382 let k_var = ProofExpr::Atom(fresh_k.clone());
3383
3384 let ih = beta_reduce(&ProofExpr::App(
3386 Box::new(motive.clone()),
3387 Box::new(k_var.clone()),
3388 ));
3389
3390 let succ_k = ProofExpr::Ctor {
3392 name: "Succ".into(),
3393 args: vec![k_var],
3394 };
3395 let step_goal_expr = beta_reduce(&ProofExpr::App(
3396 Box::new(motive.clone()),
3397 Box::new(succ_k),
3398 ));
3399
3400 let mut step_context = goal.context.clone();
3402 step_context.push(ih.clone());
3403
3404 let step_goal = ProofGoal::with_context(step_goal_expr, step_context);
3405 let step_proof = match self.try_step_case_with_equational_reasoning(&step_goal, &ih, depth)
3406 {
3407 Ok(proof) => proof,
3408 Err(_) => return Ok(None),
3409 };
3410
3411 Ok(Some(DerivationTree::new(
3412 goal.target.clone(),
3413 InferenceRule::StructuralInduction {
3414 variable: var_name.to_string(),
3415 ind_type: "Nat".to_string(),
3416 step_var: fresh_k,
3417 },
3418 vec![base_proof, step_proof],
3419 )))
3420 }
3421
3422 fn try_nat_induction(
3427 &mut self,
3428 goal: &ProofGoal,
3429 var_name: &str,
3430 depth: usize,
3431 ) -> ProofResult<Option<DerivationTree>> {
3432 let zero = ProofExpr::Ctor {
3434 name: "Zero".into(),
3435 args: vec![],
3436 };
3437
3438 let base_goal_expr = self.substitute_typed_var(&goal.target, var_name, &zero);
3440 let base_goal = ProofGoal::with_context(base_goal_expr, goal.context.clone());
3441
3442 let base_proof = match self.prove_goal(base_goal, depth + 1) {
3444 Ok(proof) => proof,
3445 Err(_) => return Ok(None), };
3447
3448 let fresh_k = self.fresh_var();
3450
3451 let k_var = ProofExpr::Atom(fresh_k.clone());
3453
3454 let succ_k = ProofExpr::Ctor {
3456 name: "Succ".into(),
3457 args: vec![k_var.clone()],
3458 };
3459
3460 let ih = self.substitute_typed_var(&goal.target, var_name, &k_var);
3462
3463 let step_goal_expr = self.substitute_typed_var(&goal.target, var_name, &succ_k);
3465
3466 let mut step_context = goal.context.clone();
3468 step_context.push(ih.clone());
3469
3470 let step_goal = ProofGoal::with_context(step_goal_expr, step_context);
3471
3472 let step_proof = match self.try_step_case_with_equational_reasoning(&step_goal, &ih, depth)
3474 {
3475 Ok(proof) => proof,
3476 Err(_) => return Ok(None), };
3478
3479 Ok(Some(DerivationTree::new(
3481 goal.target.clone(),
3482 InferenceRule::StructuralInduction {
3483 variable: var_name.to_string(),
3484 ind_type: "Nat".to_string(),
3485 step_var: fresh_k,
3486 },
3487 vec![base_proof, step_proof],
3488 )))
3489 }
3490
3491 fn try_list_induction(
3496 &mut self,
3497 goal: &ProofGoal,
3498 var_name: &str,
3499 depth: usize,
3500 ) -> ProofResult<Option<DerivationTree>> {
3501 let nil = ProofExpr::Ctor {
3503 name: "Nil".into(),
3504 args: vec![],
3505 };
3506
3507 let base_goal_expr = self.substitute_typed_var(&goal.target, var_name, &nil);
3509 let base_goal = ProofGoal::with_context(base_goal_expr, goal.context.clone());
3510
3511 let base_proof = match self.prove_goal(base_goal, depth + 1) {
3513 Ok(proof) => proof,
3514 Err(_) => return Ok(None),
3515 };
3516
3517 let fresh_h = self.fresh_var();
3519 let fresh_t = self.fresh_var();
3520
3521 let h_var = ProofExpr::Atom(fresh_h);
3522 let t_var = ProofExpr::Atom(fresh_t.clone());
3523
3524 let cons_ht = ProofExpr::Ctor {
3525 name: "Cons".into(),
3526 args: vec![h_var, t_var.clone()],
3527 };
3528
3529 let ih = self.substitute_typed_var(&goal.target, var_name, &t_var);
3531
3532 let step_goal_expr = self.substitute_typed_var(&goal.target, var_name, &cons_ht);
3534
3535 let mut step_context = goal.context.clone();
3536 step_context.push(ih.clone());
3537
3538 let step_goal = ProofGoal::with_context(step_goal_expr, step_context);
3539
3540 let step_proof = match self.try_step_case_with_equational_reasoning(&step_goal, &ih, depth)
3541 {
3542 Ok(proof) => proof,
3543 Err(_) => return Ok(None),
3544 };
3545
3546 Ok(Some(DerivationTree::new(
3547 goal.target.clone(),
3548 InferenceRule::StructuralInduction {
3549 variable: var_name.to_string(),
3550 ind_type: "List".to_string(),
3551 step_var: fresh_t,
3552 },
3553 vec![base_proof, step_proof],
3554 )))
3555 }
3556
3557 fn try_step_case_with_equational_reasoning(
3564 &mut self,
3565 goal: &ProofGoal,
3566 ih: &ProofExpr,
3567 depth: usize,
3568 ) -> ProofResult<DerivationTree> {
3569 if let Ok(proof) = self.prove_goal(goal.clone(), depth + 1) {
3571 return Ok(proof);
3572 }
3573
3574 if let ProofExpr::Identity(lhs, rhs) = &goal.target {
3576 if let Some(proof) = self.try_equational_proof(goal, lhs, rhs, ih, depth)? {
3578 return Ok(proof);
3579 }
3580 }
3581
3582 Err(ProofError::NoProofFound)
3583 }
3584
3585 fn try_equational_proof(
3593 &mut self,
3594 goal: &ProofGoal,
3595 lhs: &ProofTerm,
3596 rhs: &ProofTerm,
3597 ih: &ProofExpr,
3598 _depth: usize,
3599 ) -> ProofResult<Option<DerivationTree>> {
3600 let equations: Vec<ProofExpr> = self
3602 .knowledge_base
3603 .iter()
3604 .filter(|e| matches!(e, ProofExpr::Identity(_, _)))
3605 .cloned()
3606 .collect();
3607
3608 for eq_axiom in &equations {
3610 if let ProofExpr::Identity(_, _) = &eq_axiom {
3611 let renamed_axiom = self.rename_variables(&eq_axiom);
3613 if let ProofExpr::Identity(renamed_lhs, renamed_rhs) = renamed_axiom {
3614 if let Ok(subst) = unify_terms(&renamed_lhs, lhs) {
3618 let rewritten = self.apply_subst_to_term_with(&renamed_rhs, &subst);
3621
3622 if self.terms_equal_with_ih(&rewritten, rhs, ih) {
3624 let axiom_leaf =
3626 DerivationTree::leaf(eq_axiom.clone(), InferenceRule::PremiseMatch);
3627
3628 let ih_leaf =
3629 DerivationTree::leaf(ih.clone(), InferenceRule::PremiseMatch);
3630
3631 return Ok(Some(DerivationTree::new(
3632 goal.target.clone(),
3633 InferenceRule::PremiseMatch, vec![axiom_leaf, ih_leaf],
3635 )));
3636 }
3637 }
3638 }
3639 }
3640 }
3641
3642 Ok(None)
3643 }
3644
3645 fn terms_equal_with_ih(&self, t1: &ProofTerm, t2: &ProofTerm, ih: &ProofExpr) -> bool {
3647 if t1 == t2 {
3649 return true;
3650 }
3651
3652 if let ProofExpr::Identity(ih_lhs, ih_rhs) = ih {
3654 let t1_with_ih = self.rewrite_term_with_equation(t1, ih_lhs, ih_rhs);
3656 if &t1_with_ih == t2 {
3657 return true;
3658 }
3659
3660 let t2_with_ih = self.rewrite_term_with_equation(t2, ih_rhs, ih_lhs);
3662 if t1 == &t2_with_ih {
3663 return true;
3664 }
3665 }
3666
3667 false
3668 }
3669
3670 fn rewrite_term_with_equation(
3672 &self,
3673 term: &ProofTerm,
3674 from: &ProofTerm,
3675 to: &ProofTerm,
3676 ) -> ProofTerm {
3677 if term == from {
3679 return to.clone();
3680 }
3681
3682 match term {
3684 ProofTerm::Function(name, args) => {
3685 let new_args: Vec<ProofTerm> = args
3686 .iter()
3687 .map(|a| self.rewrite_term_with_equation(a, from, to))
3688 .collect();
3689 ProofTerm::Function(name.clone(), new_args)
3690 }
3691 ProofTerm::Group(terms) => {
3692 let new_terms: Vec<ProofTerm> = terms
3693 .iter()
3694 .map(|t| self.rewrite_term_with_equation(t, from, to))
3695 .collect();
3696 ProofTerm::Group(new_terms)
3697 }
3698 _ => term.clone(),
3699 }
3700 }
3701
3702 fn apply_subst_to_term_with(&self, term: &ProofTerm, subst: &Substitution) -> ProofTerm {
3704 match term {
3705 ProofTerm::Variable(v) => subst.get(v).cloned().unwrap_or_else(|| term.clone()),
3706 ProofTerm::Function(name, args) => ProofTerm::Function(
3707 name.clone(),
3708 args.iter()
3709 .map(|a| self.apply_subst_to_term_with(a, subst))
3710 .collect(),
3711 ),
3712 ProofTerm::Group(terms) => ProofTerm::Group(
3713 terms
3714 .iter()
3715 .map(|t| self.apply_subst_to_term_with(t, subst))
3716 .collect(),
3717 ),
3718 ProofTerm::Constant(_) => term.clone(),
3719 ProofTerm::BoundVarRef(_) => term.clone(),
3720 }
3721 }
3722
3723 fn find_typed_var(&self, expr: &ProofExpr) -> Option<(String, String)> {
3725 match expr {
3726 ProofExpr::TypedVar { name, typename } => Some((name.clone(), typename.clone())),
3727 ProofExpr::Identity(l, r) => {
3728 self.find_typed_var_in_term(l).or_else(|| self.find_typed_var_in_term(r))
3729 }
3730 ProofExpr::Predicate { args, .. } => {
3731 for arg in args {
3732 if let Some(tv) = self.find_typed_var_in_term(arg) {
3733 return Some(tv);
3734 }
3735 }
3736 None
3737 }
3738 ProofExpr::And(l, r)
3739 | ProofExpr::Or(l, r)
3740 | ProofExpr::Implies(l, r)
3741 | ProofExpr::Iff(l, r) => self.find_typed_var(l).or_else(|| self.find_typed_var(r)),
3742 ProofExpr::Not(inner) => self.find_typed_var(inner),
3743 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
3744 self.find_typed_var(body)
3745 }
3746 _ => None,
3747 }
3748 }
3749
3750 fn find_typed_var_in_term(&self, term: &ProofTerm) -> Option<(String, String)> {
3752 match term {
3753 ProofTerm::Variable(v) => {
3754 if v.contains(':') {
3758 let parts: Vec<&str> = v.splitn(2, ':').collect();
3759 if parts.len() == 2 {
3760 return Some((parts[0].to_string(), parts[1].to_string()));
3761 }
3762 }
3763 None
3764 }
3765 ProofTerm::Function(_, args) => {
3766 for arg in args {
3767 if let Some(tv) = self.find_typed_var_in_term(arg) {
3768 return Some(tv);
3769 }
3770 }
3771 None
3772 }
3773 ProofTerm::Group(terms) => {
3774 for t in terms {
3775 if let Some(tv) = self.find_typed_var_in_term(t) {
3776 return Some(tv);
3777 }
3778 }
3779 None
3780 }
3781 ProofTerm::Constant(_) => None,
3782 ProofTerm::BoundVarRef(_) => None, }
3784 }
3785
3786 fn substitute_typed_var(
3788 &self,
3789 expr: &ProofExpr,
3790 var_name: &str,
3791 replacement: &ProofExpr,
3792 ) -> ProofExpr {
3793 match expr {
3794 ProofExpr::TypedVar { name, .. } if name == var_name => replacement.clone(),
3795 ProofExpr::Identity(l, r) => {
3796 let new_l = self.substitute_typed_var_in_term(l, var_name, replacement);
3797 let new_r = self.substitute_typed_var_in_term(r, var_name, replacement);
3798 ProofExpr::Identity(new_l, new_r)
3799 }
3800 ProofExpr::Predicate { name, args, world } => {
3801 let new_args: Vec<ProofTerm> = args
3802 .iter()
3803 .map(|a| self.substitute_typed_var_in_term(a, var_name, replacement))
3804 .collect();
3805 ProofExpr::Predicate {
3806 name: name.clone(),
3807 args: new_args,
3808 world: world.clone(),
3809 }
3810 }
3811 ProofExpr::And(l, r) => ProofExpr::And(
3812 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3813 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3814 ),
3815 ProofExpr::Or(l, r) => ProofExpr::Or(
3816 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3817 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3818 ),
3819 ProofExpr::Implies(l, r) => ProofExpr::Implies(
3820 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3821 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3822 ),
3823 ProofExpr::Iff(l, r) => ProofExpr::Iff(
3824 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3825 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3826 ),
3827 ProofExpr::Not(inner) => {
3828 ProofExpr::Not(Box::new(self.substitute_typed_var(inner, var_name, replacement)))
3829 }
3830 ProofExpr::ForAll { variable, body } => ProofExpr::ForAll {
3831 variable: variable.clone(),
3832 body: Box::new(self.substitute_typed_var(body, var_name, replacement)),
3833 },
3834 ProofExpr::Exists { variable, body } => ProofExpr::Exists {
3835 variable: variable.clone(),
3836 body: Box::new(self.substitute_typed_var(body, var_name, replacement)),
3837 },
3838 _ => expr.clone(),
3839 }
3840 }
3841
3842 fn substitute_typed_var_in_term(
3844 &self,
3845 term: &ProofTerm,
3846 var_name: &str,
3847 replacement: &ProofExpr,
3848 ) -> ProofTerm {
3849 match term {
3850 ProofTerm::Variable(v) => {
3851 if v == var_name || v.starts_with(&format!("{}:", var_name)) {
3853 self.expr_to_term(replacement)
3854 } else {
3855 term.clone()
3856 }
3857 }
3858 ProofTerm::Function(name, args) => ProofTerm::Function(
3859 name.clone(),
3860 args.iter()
3861 .map(|a| self.substitute_typed_var_in_term(a, var_name, replacement))
3862 .collect(),
3863 ),
3864 ProofTerm::Group(terms) => ProofTerm::Group(
3865 terms
3866 .iter()
3867 .map(|t| self.substitute_typed_var_in_term(t, var_name, replacement))
3868 .collect(),
3869 ),
3870 ProofTerm::Constant(_) => term.clone(),
3871 ProofTerm::BoundVarRef(_) => term.clone(),
3872 }
3873 }
3874
3875 fn expr_to_term(&self, expr: &ProofExpr) -> ProofTerm {
3877 match expr {
3878 ProofExpr::Atom(s) => ProofTerm::Variable(s.clone()),
3879 ProofExpr::Ctor { name, args } => {
3880 ProofTerm::Function(name.clone(), args.iter().map(|a| self.expr_to_term(a)).collect())
3881 }
3882 ProofExpr::TypedVar { name, .. } => ProofTerm::Variable(name.clone()),
3883 _ => ProofTerm::Constant(format!("{}", expr)),
3884 }
3885 }
3886
3887 fn fresh_var(&mut self) -> String {
3893 self.var_counter += 1;
3894 format!("_G{}", self.var_counter)
3895 }
3896
3897 fn rename_variables(&mut self, expr: &ProofExpr) -> ProofExpr {
3899 let vars = self.collect_variables(expr);
3900 let mut subst = Substitution::new();
3901
3902 for var in vars {
3903 let fresh = self.fresh_var();
3904 subst.insert(var, ProofTerm::Variable(fresh));
3905 }
3906
3907 apply_subst_to_expr(expr, &subst)
3908 }
3909
3910 fn collect_variables(&self, expr: &ProofExpr) -> Vec<String> {
3912 let mut vars = Vec::new();
3913 self.collect_variables_recursive(expr, &mut vars);
3914 vars
3915 }
3916
3917 fn collect_variables_recursive(&self, expr: &ProofExpr, vars: &mut Vec<String>) {
3918 match expr {
3919 ProofExpr::Predicate { args, .. } => {
3920 for arg in args {
3921 self.collect_term_variables(arg, vars);
3922 }
3923 }
3924 ProofExpr::Identity(l, r) => {
3925 self.collect_term_variables(l, vars);
3926 self.collect_term_variables(r, vars);
3927 }
3928 ProofExpr::And(l, r)
3929 | ProofExpr::Or(l, r)
3930 | ProofExpr::Implies(l, r)
3931 | ProofExpr::Iff(l, r) => {
3932 self.collect_variables_recursive(l, vars);
3933 self.collect_variables_recursive(r, vars);
3934 }
3935 ProofExpr::Not(inner) => self.collect_variables_recursive(inner, vars),
3936 ProofExpr::ForAll { variable, body } | ProofExpr::Exists { variable, body } => {
3937 if !vars.contains(variable) {
3938 vars.push(variable.clone());
3939 }
3940 self.collect_variables_recursive(body, vars);
3941 }
3942 ProofExpr::Lambda { variable, body } => {
3943 if !vars.contains(variable) {
3944 vars.push(variable.clone());
3945 }
3946 self.collect_variables_recursive(body, vars);
3947 }
3948 ProofExpr::App(f, a) => {
3949 self.collect_variables_recursive(f, vars);
3950 self.collect_variables_recursive(a, vars);
3951 }
3952 ProofExpr::NeoEvent { roles, .. } => {
3953 for (_, term) in roles {
3954 self.collect_term_variables(term, vars);
3955 }
3956 }
3957 _ => {}
3958 }
3959 }
3960
3961 fn collect_term_variables(&self, term: &ProofTerm, vars: &mut Vec<String>) {
3962 match term {
3963 ProofTerm::Variable(v) => {
3964 if !vars.contains(v) {
3965 vars.push(v.clone());
3966 }
3967 }
3968 ProofTerm::Function(_, args) => {
3969 for arg in args {
3970 self.collect_term_variables(arg, vars);
3971 }
3972 }
3973 ProofTerm::Group(terms) => {
3974 for t in terms {
3975 self.collect_term_variables(t, vars);
3976 }
3977 }
3978 ProofTerm::Constant(_) => {}
3979 ProofTerm::BoundVarRef(_) => {} }
3981 }
3982
3983 fn collect_witnesses(&self) -> Vec<ProofTerm> {
3985 let mut witnesses = Vec::new();
3986
3987 for expr in &self.knowledge_base {
3988 self.collect_constants_from_expr(expr, &mut witnesses);
3989 }
3990
3991 witnesses
3992 }
3993
3994 fn collect_constants_from_expr(&self, expr: &ProofExpr, constants: &mut Vec<ProofTerm>) {
3995 match expr {
3996 ProofExpr::Predicate { args, .. } => {
3997 for arg in args {
3998 self.collect_constants_from_term(arg, constants);
3999 }
4000 }
4001 ProofExpr::Identity(l, r) => {
4002 self.collect_constants_from_term(l, constants);
4003 self.collect_constants_from_term(r, constants);
4004 }
4005 ProofExpr::And(l, r)
4006 | ProofExpr::Or(l, r)
4007 | ProofExpr::Implies(l, r)
4008 | ProofExpr::Iff(l, r) => {
4009 self.collect_constants_from_expr(l, constants);
4010 self.collect_constants_from_expr(r, constants);
4011 }
4012 ProofExpr::Not(inner) => self.collect_constants_from_expr(inner, constants),
4013 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
4014 self.collect_constants_from_expr(body, constants);
4015 }
4016 ProofExpr::NeoEvent { roles, .. } => {
4017 for (_, term) in roles {
4018 self.collect_constants_from_term(term, constants);
4019 }
4020 }
4021 _ => {}
4022 }
4023 }
4024
4025 fn collect_constants_from_term(&self, term: &ProofTerm, constants: &mut Vec<ProofTerm>) {
4026 match term {
4027 ProofTerm::Constant(_) => {
4028 if !constants.contains(term) {
4029 constants.push(term.clone());
4030 }
4031 }
4032 ProofTerm::Function(_, args) => {
4033 if !constants.contains(term) {
4035 constants.push(term.clone());
4036 }
4037 for arg in args {
4038 self.collect_constants_from_term(arg, constants);
4039 }
4040 }
4041 ProofTerm::Group(terms) => {
4042 for t in terms {
4043 self.collect_constants_from_term(t, constants);
4044 }
4045 }
4046 ProofTerm::Variable(_) => {}
4047 ProofTerm::BoundVarRef(_) => {} }
4049 }
4050
4051 #[cfg(feature = "verification")]
4060 fn try_oracle_fallback(&self, goal: &ProofGoal) -> ProofResult<Option<DerivationTree>> {
4061 crate::oracle::try_oracle(goal, &self.knowledge_base)
4062 }
4063}
4064
4065fn extract_type_from_exists_body(body: &ProofExpr) -> Option<String> {
4075 match body {
4076 ProofExpr::TypedVar { typename, .. } => Some(typename.clone()),
4078
4079 ProofExpr::And(l, r) => {
4081 extract_type_from_exists_body(l).or_else(|| extract_type_from_exists_body(r))
4082 }
4083
4084 ProofExpr::Or(l, r) => {
4086 extract_type_from_exists_body(l).or_else(|| extract_type_from_exists_body(r))
4087 }
4088
4089 ProofExpr::Exists { body, .. } | ProofExpr::ForAll { body, .. } => {
4091 extract_type_from_exists_body(body)
4092 }
4093
4094 _ => None,
4096 }
4097}
4098
4099impl Default for BackwardChainer {
4100 fn default() -> Self {
4101 Self::new()
4102 }
4103}