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 _ => expr.clone(),
2089 }
2090 }
2091
2092 fn abstract_event_to_predicate(&self, expr: &ProofExpr) -> Option<ProofExpr> {
2103 match expr {
2104 ProofExpr::NeoEvent { verb, roles, .. } => {
2106 let agent = roles.iter()
2108 .find(|(role, _)| role == "Agent")
2109 .map(|(_, term)| term.clone());
2110
2111 let theme = roles.iter()
2112 .find(|(role, _)| role == "Theme" || role == "Patient")
2113 .map(|(_, term)| term.clone());
2114
2115 let mut args = Vec::new();
2117 if let Some(a) = agent {
2118 args.push(a);
2119 }
2120 if let Some(t) = theme {
2121 args.push(t);
2122 }
2123
2124 let pred_name = verb.to_lowercase();
2126
2127 Some(ProofExpr::Predicate {
2128 name: pred_name,
2129 args,
2130 world: None,
2131 })
2132 }
2133
2134 ProofExpr::Exists { variable, body } => {
2136 if !self.is_event_variable(variable) {
2138 return None;
2139 }
2140
2141 if let Some(abstracted) = self.abstract_event_to_predicate(body) {
2143 return Some(abstracted);
2144 }
2145
2146 if let Some(abstracted) = self.abstract_event_conjunction(variable, body) {
2149 return Some(abstracted);
2150 }
2151
2152 None
2153 }
2154
2155 _ => None,
2156 }
2157 }
2158
2159 fn abstract_event_conjunction(&self, event_var: &str, body: &ProofExpr) -> Option<ProofExpr> {
2163 let mut components = Vec::new();
2165 self.flatten_conjunction(body, &mut components);
2166
2167 let mut verb_name: Option<String> = None;
2169 let mut agent: Option<ProofTerm> = None;
2170 let mut theme: Option<ProofTerm> = None;
2171
2172 for comp in &components {
2173 if let ProofExpr::Predicate { name, args, .. } = comp {
2174 let first_is_event = args.first().map_or(false, |arg| {
2176 matches!(arg, ProofTerm::Variable(v) | ProofTerm::BoundVarRef(v) if v == event_var)
2177 });
2178
2179 if !first_is_event && args.len() == 1 {
2180 if let Some(ProofTerm::Variable(v) | ProofTerm::BoundVarRef(v)) = args.first() {
2182 if v == event_var {
2183 verb_name = Some(name.clone());
2184 continue;
2185 }
2186 }
2187 }
2188
2189 if first_is_event {
2190 match name.as_str() {
2191 "Agent" if args.len() == 2 => {
2192 agent = Some(args[1].clone());
2193 }
2194 "Theme" | "Patient" if args.len() == 2 => {
2195 theme = Some(args[1].clone());
2196 }
2197 _ if args.len() == 1 && verb_name.is_none() => {
2198 verb_name = Some(name.clone());
2200 }
2201 _ => {}
2202 }
2203 }
2204 }
2205 }
2206
2207 if let Some(verb) = verb_name {
2209 let mut args = Vec::new();
2210 if let Some(a) = agent {
2211 args.push(a);
2212 }
2213 if let Some(t) = theme {
2214 args.push(t);
2215 }
2216
2217 return Some(ProofExpr::Predicate {
2218 name: verb.to_lowercase(),
2219 args,
2220 world: None,
2221 });
2222 }
2223
2224 None
2225 }
2226
2227 fn is_event_variable(&self, var: &str) -> bool {
2231 var == "e" || var.starts_with("e_") ||
2232 (var.starts_with('e') && var.len() == 2 && var.chars().nth(1).map_or(false, |c| c.is_ascii_digit()))
2233 }
2234
2235 fn abstract_all_events(&self, expr: &ProofExpr) -> ProofExpr {
2240 if let Some(abstracted) = self.abstract_event_to_predicate(expr) {
2242 return abstracted;
2243 }
2244
2245 match expr {
2247 ProofExpr::And(left, right) => ProofExpr::And(
2248 Box::new(self.abstract_all_events(left)),
2249 Box::new(self.abstract_all_events(right)),
2250 ),
2251 ProofExpr::Or(left, right) => ProofExpr::Or(
2252 Box::new(self.abstract_all_events(left)),
2253 Box::new(self.abstract_all_events(right)),
2254 ),
2255 ProofExpr::Implies(left, right) => ProofExpr::Implies(
2256 Box::new(self.abstract_all_events(left)),
2257 Box::new(self.abstract_all_events(right)),
2258 ),
2259 ProofExpr::Iff(left, right) => ProofExpr::Iff(
2260 Box::new(self.abstract_all_events(left)),
2261 Box::new(self.abstract_all_events(right)),
2262 ),
2263 ProofExpr::Not(inner) => {
2264 if let ProofExpr::Exists { variable, body } = inner.as_ref() {
2268 return ProofExpr::ForAll {
2269 variable: variable.clone(),
2270 body: Box::new(self.abstract_all_events(&ProofExpr::Not(body.clone()))),
2271 };
2272 }
2273 ProofExpr::Not(Box::new(self.abstract_all_events(inner)))
2276 }
2277 ProofExpr::ForAll { variable, body } => {
2278 if let ProofExpr::Not(inner) = body.as_ref() {
2281 if let ProofExpr::And(left, right) = inner.as_ref() {
2282 return ProofExpr::ForAll {
2283 variable: variable.clone(),
2284 body: Box::new(ProofExpr::Implies(
2285 Box::new(self.abstract_all_events(left)),
2286 Box::new(self.abstract_all_events(&ProofExpr::Not(right.clone()))),
2287 )),
2288 };
2289 }
2290 }
2291 ProofExpr::ForAll {
2292 variable: variable.clone(),
2293 body: Box::new(self.abstract_all_events(body)),
2294 }
2295 }
2296 ProofExpr::Exists { variable, body } => {
2297 if self.is_event_variable(variable) {
2299 if let Some(abstracted) = self.abstract_event_to_predicate(body) {
2300 return abstracted;
2301 }
2302 }
2303 ProofExpr::Exists {
2305 variable: variable.clone(),
2306 body: Box::new(self.abstract_all_events(body)),
2307 }
2308 }
2309 other => other.clone(),
2311 }
2312 }
2313
2314 fn abstract_events_only(&self, expr: &ProofExpr) -> ProofExpr {
2319 if let Some(abstracted) = self.abstract_event_to_predicate(expr) {
2321 return abstracted;
2322 }
2323
2324 match expr {
2326 ProofExpr::And(left, right) => ProofExpr::And(
2327 Box::new(self.abstract_events_only(left)),
2328 Box::new(self.abstract_events_only(right)),
2329 ),
2330 ProofExpr::Or(left, right) => ProofExpr::Or(
2331 Box::new(self.abstract_events_only(left)),
2332 Box::new(self.abstract_events_only(right)),
2333 ),
2334 ProofExpr::Implies(left, right) => ProofExpr::Implies(
2335 Box::new(self.abstract_events_only(left)),
2336 Box::new(self.abstract_events_only(right)),
2337 ),
2338 ProofExpr::Iff(left, right) => ProofExpr::Iff(
2339 Box::new(self.abstract_events_only(left)),
2340 Box::new(self.abstract_events_only(right)),
2341 ),
2342 ProofExpr::Not(inner) => {
2343 ProofExpr::Not(Box::new(self.abstract_events_only(inner)))
2345 }
2346 ProofExpr::ForAll { variable, body } => ProofExpr::ForAll {
2347 variable: variable.clone(),
2348 body: Box::new(self.abstract_events_only(body)),
2349 },
2350 ProofExpr::Exists { variable, body } => {
2351 if self.is_event_variable(variable) {
2353 if let Some(abstracted) = self.abstract_event_to_predicate(body) {
2354 return abstracted;
2355 }
2356 }
2357 ProofExpr::Exists {
2359 variable: variable.clone(),
2360 body: Box::new(self.abstract_events_only(body)),
2361 }
2362 }
2363 other => other.clone(),
2365 }
2366 }
2367
2368 fn find_contradiction(
2372 &mut self,
2373 context: &[ProofExpr],
2374 depth: usize,
2375 ) -> ProofResult<Option<DerivationTree>> {
2376 let all_exprs: Vec<ProofExpr> = self.knowledge_base.iter()
2378 .chain(context.iter())
2379 .cloned()
2380 .collect();
2381
2382 for expr in &all_exprs {
2384 if let ProofExpr::Not(inner) = expr {
2385 for other in &all_exprs {
2387 if exprs_structurally_equal(other, inner) {
2388 let pos_leaf = DerivationTree::leaf(
2390 (**inner).clone(),
2391 InferenceRule::PremiseMatch,
2392 );
2393 let neg_leaf = DerivationTree::leaf(
2394 expr.clone(),
2395 InferenceRule::PremiseMatch,
2396 );
2397 return Ok(Some(DerivationTree::new(
2398 ProofExpr::Atom("⊥".into()),
2399 InferenceRule::Contradiction,
2400 vec![pos_leaf, neg_leaf],
2401 )));
2402 }
2403 }
2404 }
2405 }
2406
2407 let mut implications: Vec<(ProofExpr, ProofExpr)> = Vec::new();
2412 for e in &all_exprs {
2413 if let ProofExpr::Implies(ante, cons) = e {
2414 implications.push(((**ante).clone(), (**cons).clone()));
2415 }
2416 if let ProofExpr::ForAll { body, .. } = e {
2418 if let ProofExpr::Implies(ante, cons) = body.as_ref() {
2419 implications.push(((**ante).clone(), (**cons).clone()));
2420 }
2421 }
2422 }
2423
2424 for fact in context {
2426 let mut derivable_consequences: Vec<ProofExpr> = Vec::new();
2428
2429 for (ante, cons) in &implications {
2430 if let Ok(subst) = unify_exprs(fact, ante) {
2432 let instantiated_cons = apply_subst_to_expr(cons, &subst);
2433 derivable_consequences.push(instantiated_cons);
2434 }
2435
2436 if let ProofExpr::And(left, right) = ante {
2438 if let Some(subst) = self.try_match_conjunction_antecedent(
2440 left, right, &all_exprs
2441 ) {
2442 let instantiated_cons = apply_subst_to_expr(cons, &subst);
2443 if !derivable_consequences.contains(&instantiated_cons) {
2444 derivable_consequences.push(instantiated_cons);
2445 }
2446 }
2447 }
2448 }
2449
2450 for cons in &derivable_consequences {
2452 if let ProofExpr::Not(inner) = cons {
2454 if exprs_structurally_equal(inner, fact) {
2455 let pos_leaf = DerivationTree::leaf(
2458 fact.clone(),
2459 InferenceRule::PremiseMatch,
2460 );
2461 let neg_leaf = DerivationTree::leaf(
2462 cons.clone(),
2463 InferenceRule::ModusPonens,
2464 );
2465 return Ok(Some(DerivationTree::new(
2466 ProofExpr::Atom("⊥".into()),
2467 InferenceRule::Contradiction,
2468 vec![pos_leaf, neg_leaf],
2469 )));
2470 }
2471 }
2472
2473 for other in context {
2475 if std::ptr::eq(fact as *const _, other as *const _) {
2476 continue; }
2478 if let ProofExpr::Not(inner) = cons {
2480 if exprs_structurally_equal(inner, other) {
2481 let pos_leaf = DerivationTree::leaf(
2482 other.clone(),
2483 InferenceRule::PremiseMatch,
2484 );
2485 let neg_leaf = DerivationTree::leaf(
2486 cons.clone(),
2487 InferenceRule::ModusPonens,
2488 );
2489 return Ok(Some(DerivationTree::new(
2490 ProofExpr::Atom("⊥".into()),
2491 InferenceRule::Contradiction,
2492 vec![pos_leaf, neg_leaf],
2493 )));
2494 }
2495 }
2496 if let ProofExpr::Not(inner_other) = other {
2498 if exprs_structurally_equal(inner_other, cons) {
2499 let pos_leaf = DerivationTree::leaf(
2500 cons.clone(),
2501 InferenceRule::ModusPonens,
2502 );
2503 let neg_leaf = DerivationTree::leaf(
2504 other.clone(),
2505 InferenceRule::PremiseMatch,
2506 );
2507 return Ok(Some(DerivationTree::new(
2508 ProofExpr::Atom("⊥".into()),
2509 InferenceRule::Contradiction,
2510 vec![pos_leaf, neg_leaf],
2511 )));
2512 }
2513 }
2514 }
2515 }
2516
2517 for i in 0..derivable_consequences.len() {
2519 for j in (i + 1)..derivable_consequences.len() {
2520 let cons1 = &derivable_consequences[i];
2521 let cons2 = &derivable_consequences[j];
2522
2523 if let ProofExpr::Not(inner1) = cons1 {
2525 if exprs_structurally_equal(inner1, cons2) {
2526 let pos_leaf = DerivationTree::leaf(
2528 cons2.clone(),
2529 InferenceRule::ModusPonens,
2530 );
2531 let neg_leaf = DerivationTree::leaf(
2532 cons1.clone(),
2533 InferenceRule::ModusPonens,
2534 );
2535 return Ok(Some(DerivationTree::new(
2536 ProofExpr::Atom("⊥".into()),
2537 InferenceRule::Contradiction,
2538 vec![pos_leaf, neg_leaf],
2539 )));
2540 }
2541 }
2542 if let ProofExpr::Not(inner2) = cons2 {
2543 if exprs_structurally_equal(inner2, cons1) {
2544 let pos_leaf = DerivationTree::leaf(
2546 cons1.clone(),
2547 InferenceRule::ModusPonens,
2548 );
2549 let neg_leaf = DerivationTree::leaf(
2550 cons2.clone(),
2551 InferenceRule::ModusPonens,
2552 );
2553 return Ok(Some(DerivationTree::new(
2554 ProofExpr::Atom("⊥".into()),
2555 InferenceRule::Contradiction,
2556 vec![pos_leaf, neg_leaf],
2557 )));
2558 }
2559 }
2560 }
2561 }
2562 }
2563
2564 if let Some(proof) = self.find_self_referential_contradiction(context, depth)? {
2566 return Ok(Some(proof));
2567 }
2568
2569 Ok(None)
2570 }
2571
2572 fn try_match_conjunction_antecedent(
2577 &self,
2578 left: &ProofExpr,
2579 right: &ProofExpr,
2580 facts: &[ProofExpr],
2581 ) -> Option<Substitution> {
2582 for fact1 in facts {
2584 if let Ok(subst1) = unify_exprs(fact1, left) {
2585 let instantiated_right = apply_subst_to_expr(right, &subst1);
2587 for fact2 in facts {
2589 if let Ok(subst2) = unify_exprs(fact2, &instantiated_right) {
2590 let mut combined = subst1.clone();
2592 for (k, v) in subst2.iter() {
2593 combined.insert(k.clone(), v.clone());
2594 }
2595 return Some(combined);
2596 }
2597 }
2598 }
2599 }
2600 for fact1 in facts {
2602 if let Ok(subst1) = unify_exprs(fact1, right) {
2603 let instantiated_left = apply_subst_to_expr(left, &subst1);
2604 for fact2 in facts {
2605 if let Ok(subst2) = unify_exprs(fact2, &instantiated_left) {
2606 let mut combined = subst1.clone();
2607 for (k, v) in subst2.iter() {
2608 combined.insert(k.clone(), v.clone());
2609 }
2610 return Some(combined);
2611 }
2612 }
2613 }
2614 }
2615 None
2616 }
2617
2618 fn find_self_referential_contradiction(
2626 &mut self,
2627 context: &[ProofExpr],
2628 _depth: usize,
2629 ) -> ProofResult<Option<DerivationTree>> {
2630 let all_exprs: Vec<ProofExpr> = self.knowledge_base.iter()
2632 .chain(context.iter())
2633 .cloned()
2634 .collect();
2635
2636 for expr1 in &all_exprs {
2639 if let ProofExpr::ForAll { variable: var1, body: body1 } = expr1 {
2640 if let ProofExpr::Implies(ante1, cons1) = body1.as_ref() {
2641 for expr2 in &all_exprs {
2642 if std::ptr::eq(expr1, expr2) {
2643 continue; }
2645 if let ProofExpr::ForAll { variable: var2, body: body2 } = expr2 {
2646 if let ProofExpr::Implies(ante2, cons2) = body2.as_ref() {
2647 if let ProofExpr::Not(neg_cons2) = cons2.as_ref() {
2649 let witnesses = self.extract_constants_from_expr(cons1);
2655
2656 for witness_name in &witnesses {
2657 let witness = ProofTerm::Constant(witness_name.clone());
2658
2659 let mut subst1 = Substitution::new();
2661 subst1.insert(var1.clone(), witness.clone());
2662 let ante1_inst = apply_subst_to_expr(ante1, &subst1);
2663 let cons1_inst = apply_subst_to_expr(cons1, &subst1);
2664
2665 let mut subst2 = Substitution::new();
2666 subst2.insert(var2.clone(), witness.clone());
2667 let ante2_inst = apply_subst_to_expr(ante2, &subst2);
2668 let cons2_inst = apply_subst_to_expr(cons2, &subst2);
2669
2670 if let ProofExpr::Not(inner2) = &cons2_inst {
2673 if exprs_structurally_equal(&cons1_inst, inner2) {
2674 if self.are_complements(&ante1_inst, &ante2_inst) {
2686 let pos_leaf = DerivationTree::leaf(
2690 cons1_inst.clone(),
2691 InferenceRule::ModusPonens,
2692 );
2693 let neg_leaf = DerivationTree::leaf(
2694 cons2_inst,
2695 InferenceRule::ModusPonens,
2696 );
2697 return Ok(Some(DerivationTree::new(
2698 ProofExpr::Atom("⊥".into()),
2699 InferenceRule::Contradiction,
2700 vec![pos_leaf, neg_leaf],
2701 )));
2702 }
2703 }
2704 }
2705 }
2706 }
2707 }
2708 }
2709 }
2710 }
2711 }
2712 }
2713
2714 Ok(None)
2715 }
2716
2717 fn are_complements(&self, expr1: &ProofExpr, expr2: &ProofExpr) -> bool {
2719 if let ProofExpr::Not(inner1) = expr1 {
2721 if exprs_structurally_equal(inner1, expr2) {
2722 return true;
2723 }
2724 }
2725 if let ProofExpr::Not(inner2) = expr2 {
2727 if exprs_structurally_equal(inner2, expr1) {
2728 return true;
2729 }
2730 }
2731 false
2732 }
2733
2734 fn extract_constants_from_expr(&self, expr: &ProofExpr) -> Vec<String> {
2736 let mut constants = Vec::new();
2737 self.extract_constants_recursive(expr, &mut constants);
2738 constants
2739 }
2740
2741 fn extract_constants_recursive(&self, expr: &ProofExpr, constants: &mut Vec<String>) {
2742 match expr {
2743 ProofExpr::Predicate { args, .. } => {
2744 for arg in args {
2745 self.extract_constants_from_term_recursive(arg, constants);
2746 }
2747 }
2748 ProofExpr::Identity(l, r) => {
2749 self.extract_constants_from_term_recursive(l, constants);
2750 self.extract_constants_from_term_recursive(r, constants);
2751 }
2752 ProofExpr::And(l, r)
2753 | ProofExpr::Or(l, r)
2754 | ProofExpr::Implies(l, r)
2755 | ProofExpr::Iff(l, r) => {
2756 self.extract_constants_recursive(l, constants);
2757 self.extract_constants_recursive(r, constants);
2758 }
2759 ProofExpr::Not(inner) => {
2760 self.extract_constants_recursive(inner, constants);
2761 }
2762 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
2763 self.extract_constants_recursive(body, constants);
2764 }
2765 _ => {}
2766 }
2767 }
2768
2769 fn extract_constants_from_term_recursive(&self, term: &ProofTerm, constants: &mut Vec<String>) {
2770 match term {
2771 ProofTerm::Constant(name) => {
2772 if !constants.contains(name) {
2773 constants.push(name.clone());
2774 }
2775 }
2776 ProofTerm::Function(_, args) => {
2777 for arg in args {
2778 self.extract_constants_from_term_recursive(arg, constants);
2779 }
2780 }
2781 ProofTerm::Group(terms) => {
2782 for t in terms {
2783 self.extract_constants_from_term_recursive(t, constants);
2784 }
2785 }
2786 _ => {}
2787 }
2788 }
2789
2790 fn try_equality_rewrite(
2799 &mut self,
2800 goal: &ProofGoal,
2801 depth: usize,
2802 ) -> ProofResult<Option<DerivationTree>> {
2803 let equalities: Vec<(ProofTerm, ProofTerm)> = self
2805 .knowledge_base
2806 .iter()
2807 .chain(goal.context.iter())
2808 .filter_map(|expr| {
2809 if let ProofExpr::Identity(l, r) = expr {
2810 Some((l.clone(), r.clone()))
2811 } else {
2812 None
2813 }
2814 })
2815 .collect();
2816
2817 if equalities.is_empty() {
2818 return Ok(None);
2819 }
2820
2821 if let ProofExpr::Identity(goal_l, goal_r) = &goal.target {
2823 if let Some(tree) = self.try_equality_symmetry(goal_l, goal_r, &equalities, depth)? {
2825 return Ok(Some(tree));
2826 }
2827
2828 if let Some(tree) = self.try_equality_transitivity(goal_l, goal_r, &equalities, depth)? {
2830 return Ok(Some(tree));
2831 }
2832
2833 if depth + 3 < self.max_depth {
2836 if let Some(tree) = self.try_equational_identity_rewrite(goal, goal_l, goal_r, depth)? {
2837 return Ok(Some(tree));
2838 }
2839 }
2840
2841 return Ok(None);
2842 }
2843
2844 for (eq_from, eq_to) in &equalities {
2846 if let Some(tree) = self.try_rewrite_with_equality(
2848 goal, eq_from, eq_to, depth,
2849 )? {
2850 return Ok(Some(tree));
2851 }
2852
2853 if let Some(tree) = self.try_rewrite_with_equality(
2855 goal, eq_to, eq_from, depth,
2856 )? {
2857 return Ok(Some(tree));
2858 }
2859 }
2860
2861 Ok(None)
2862 }
2863
2864 fn try_rewrite_with_equality(
2866 &mut self,
2867 goal: &ProofGoal,
2868 from: &ProofTerm,
2869 to: &ProofTerm,
2870 depth: usize,
2871 ) -> ProofResult<Option<DerivationTree>> {
2872 let source_goal = self.substitute_term_in_expr(&goal.target, to, from);
2875
2876 if source_goal == goal.target {
2878 return Ok(None);
2879 }
2880
2881 let source_proof_goal = ProofGoal::with_context(source_goal.clone(), goal.context.clone());
2883 if let Ok(source_proof) = self.prove_goal(source_proof_goal, depth + 1) {
2884 let equality = ProofExpr::Identity(from.clone(), to.clone());
2886 let eq_proof_goal = ProofGoal::with_context(equality.clone(), goal.context.clone());
2887
2888 if let Ok(eq_proof) = self.prove_goal(eq_proof_goal, depth + 1) {
2889 return Ok(Some(DerivationTree::new(
2890 goal.target.clone(),
2891 InferenceRule::Rewrite {
2892 from: from.clone(),
2893 to: to.clone(),
2894 },
2895 vec![eq_proof, source_proof],
2896 )));
2897 }
2898 }
2899
2900 Ok(None)
2901 }
2902
2903 fn try_equality_symmetry(
2905 &mut self,
2906 goal_l: &ProofTerm,
2907 goal_r: &ProofTerm,
2908 equalities: &[(ProofTerm, ProofTerm)],
2909 _depth: usize,
2910 ) -> ProofResult<Option<DerivationTree>> {
2911 for (eq_l, eq_r) in equalities {
2913 if eq_l == goal_r && eq_r == goal_l {
2914 let source = ProofExpr::Identity(goal_r.clone(), goal_l.clone());
2916 return Ok(Some(DerivationTree::new(
2917 ProofExpr::Identity(goal_l.clone(), goal_r.clone()),
2918 InferenceRule::EqualitySymmetry,
2919 vec![DerivationTree::leaf(source, InferenceRule::PremiseMatch)],
2920 )));
2921 }
2922 }
2923 Ok(None)
2924 }
2925
2926 fn try_equality_transitivity(
2928 &mut self,
2929 goal_l: &ProofTerm,
2930 goal_r: &ProofTerm,
2931 equalities: &[(ProofTerm, ProofTerm)],
2932 _depth: usize,
2933 ) -> ProofResult<Option<DerivationTree>> {
2934 for (eq1_l, eq1_r) in equalities {
2936 if eq1_l == goal_l {
2937 for (eq2_l, eq2_r) in equalities {
2939 if eq2_l == eq1_r && eq2_r == goal_r {
2940 let premise1 = ProofExpr::Identity(eq1_l.clone(), eq1_r.clone());
2942 let premise2 = ProofExpr::Identity(eq2_l.clone(), eq2_r.clone());
2943 return Ok(Some(DerivationTree::new(
2944 ProofExpr::Identity(goal_l.clone(), goal_r.clone()),
2945 InferenceRule::EqualityTransitivity,
2946 vec![
2947 DerivationTree::leaf(premise1, InferenceRule::PremiseMatch),
2948 DerivationTree::leaf(premise2, InferenceRule::PremiseMatch),
2949 ],
2950 )));
2951 }
2952 }
2953 }
2954 }
2955 Ok(None)
2956 }
2957
2958 fn try_equational_identity_rewrite(
2963 &mut self,
2964 goal: &ProofGoal,
2965 goal_l: &ProofTerm,
2966 goal_r: &ProofTerm,
2967 depth: usize,
2968 ) -> ProofResult<Option<DerivationTree>> {
2969 if let (
2972 ProofTerm::Function(name_l, args_l),
2973 ProofTerm::Function(name_r, args_r),
2974 ) = (goal_l, goal_r)
2975 {
2976 if name_l == name_r && args_l.len() == args_r.len() {
2977 let mut arg_proofs = Vec::new();
2979 let mut all_ok = true;
2980 for (arg_l, arg_r) in args_l.iter().zip(args_r.iter()) {
2981 let arg_goal_expr = ProofExpr::Identity(arg_l.clone(), arg_r.clone());
2982 let arg_goal = ProofGoal::with_context(arg_goal_expr, goal.context.clone());
2983 match self.prove_goal(arg_goal, depth + 1) {
2984 Ok(proof) => arg_proofs.push(proof),
2985 Err(_) => {
2986 all_ok = false;
2987 break;
2988 }
2989 }
2990 }
2991 if all_ok {
2992 return Ok(Some(DerivationTree::new(
2994 goal.target.clone(),
2995 InferenceRule::Reflexivity, arg_proofs,
2997 )));
2998 }
2999 }
3000 }
3001 let axioms: Vec<(ProofTerm, ProofTerm)> = self
3003 .knowledge_base
3004 .iter()
3005 .filter_map(|e| {
3006 if let ProofExpr::Identity(l, r) = e {
3007 Some((l.clone(), r.clone()))
3008 } else {
3009 None
3010 }
3011 })
3012 .collect();
3013
3014 for (axiom_l, axiom_r) in &axioms {
3016 let mut var_map = std::collections::HashMap::new();
3018 let renamed_l = self.rename_term_vars_with_map(axiom_l, &mut var_map);
3019 let renamed_r = self.rename_term_vars_with_map(axiom_r, &mut var_map);
3020
3021 if let Ok(subst) = unify_terms(&renamed_l, goal_l) {
3025 let rewritten = self.apply_subst_to_term(&renamed_r, &subst);
3027
3028 if terms_structurally_equal(&rewritten, goal_r) {
3030 let axiom_expr = ProofExpr::Identity(axiom_l.clone(), axiom_r.clone());
3032 return Ok(Some(DerivationTree::new(
3033 goal.target.clone(),
3034 InferenceRule::Rewrite {
3035 from: goal_l.clone(),
3036 to: rewritten,
3037 },
3038 vec![DerivationTree::leaf(axiom_expr, InferenceRule::PremiseMatch)],
3039 )));
3040 }
3041
3042 let new_goal_expr = ProofExpr::Identity(rewritten.clone(), goal_r.clone());
3044 let new_goal = ProofGoal::with_context(new_goal_expr.clone(), goal.context.clone());
3045
3046 if let Ok(sub_proof) = self.prove_goal(new_goal, depth + 1) {
3048 let axiom_expr = ProofExpr::Identity(axiom_l.clone(), axiom_r.clone());
3050 return Ok(Some(DerivationTree::new(
3051 goal.target.clone(),
3052 InferenceRule::Rewrite {
3053 from: goal_l.clone(),
3054 to: rewritten,
3055 },
3056 vec![
3057 DerivationTree::leaf(axiom_expr, InferenceRule::PremiseMatch),
3058 sub_proof,
3059 ],
3060 )));
3061 }
3062 }
3063 }
3064
3065 Ok(None)
3066 }
3067
3068 fn rename_term_vars(&mut self, term: &ProofTerm) -> ProofTerm {
3070 let mut var_map = std::collections::HashMap::new();
3071 self.rename_term_vars_with_map(term, &mut var_map)
3072 }
3073
3074 fn rename_term_vars_with_map(
3075 &mut self,
3076 term: &ProofTerm,
3077 var_map: &mut std::collections::HashMap<String, String>,
3078 ) -> ProofTerm {
3079 match term {
3080 ProofTerm::Variable(name) => {
3081 if let Some(fresh) = var_map.get(name) {
3083 ProofTerm::Variable(fresh.clone())
3084 } else {
3085 let fresh = format!("_v{}", self.var_counter);
3087 self.var_counter += 1;
3088 var_map.insert(name.clone(), fresh.clone());
3089 ProofTerm::Variable(fresh)
3090 }
3091 }
3092 ProofTerm::Function(name, args) => {
3093 ProofTerm::Function(
3094 name.clone(),
3095 args.iter().map(|a| self.rename_term_vars_with_map(a, var_map)).collect(),
3096 )
3097 }
3098 ProofTerm::Group(terms) => {
3099 ProofTerm::Group(
3100 terms.iter().map(|t| self.rename_term_vars_with_map(t, var_map)).collect(),
3101 )
3102 }
3103 other => other.clone(),
3104 }
3105 }
3106
3107 fn apply_subst_to_term(&self, term: &ProofTerm, subst: &Substitution) -> ProofTerm {
3109 match term {
3110 ProofTerm::Variable(name) => {
3111 if let Some(replacement) = subst.get(name) {
3112 replacement.clone()
3113 } else {
3114 term.clone()
3115 }
3116 }
3117 ProofTerm::Function(name, args) => {
3118 ProofTerm::Function(
3119 name.clone(),
3120 args.iter().map(|a| self.apply_subst_to_term(a, subst)).collect(),
3121 )
3122 }
3123 ProofTerm::Group(terms) => {
3124 ProofTerm::Group(terms.iter().map(|t| self.apply_subst_to_term(t, subst)).collect())
3125 }
3126 other => other.clone(),
3127 }
3128 }
3129
3130 fn substitute_term_in_expr(
3132 &self,
3133 expr: &ProofExpr,
3134 from: &ProofTerm,
3135 to: &ProofTerm,
3136 ) -> ProofExpr {
3137 match expr {
3138 ProofExpr::Predicate { name, args, world } => {
3139 let new_args: Vec<_> = args
3140 .iter()
3141 .map(|arg| self.substitute_in_term(arg, from, to))
3142 .collect();
3143 ProofExpr::Predicate {
3144 name: name.clone(),
3145 args: new_args,
3146 world: world.clone(),
3147 }
3148 }
3149 ProofExpr::Identity(l, r) => ProofExpr::Identity(
3150 self.substitute_in_term(l, from, to),
3151 self.substitute_in_term(r, from, to),
3152 ),
3153 ProofExpr::And(l, r) => ProofExpr::And(
3154 Box::new(self.substitute_term_in_expr(l, from, to)),
3155 Box::new(self.substitute_term_in_expr(r, from, to)),
3156 ),
3157 ProofExpr::Or(l, r) => ProofExpr::Or(
3158 Box::new(self.substitute_term_in_expr(l, from, to)),
3159 Box::new(self.substitute_term_in_expr(r, from, to)),
3160 ),
3161 ProofExpr::Implies(l, r) => ProofExpr::Implies(
3162 Box::new(self.substitute_term_in_expr(l, from, to)),
3163 Box::new(self.substitute_term_in_expr(r, from, to)),
3164 ),
3165 ProofExpr::Not(inner) => {
3166 ProofExpr::Not(Box::new(self.substitute_term_in_expr(inner, from, to)))
3167 }
3168 ProofExpr::ForAll { variable, body } => ProofExpr::ForAll {
3169 variable: variable.clone(),
3170 body: Box::new(self.substitute_term_in_expr(body, from, to)),
3171 },
3172 ProofExpr::Exists { variable, body } => ProofExpr::Exists {
3173 variable: variable.clone(),
3174 body: Box::new(self.substitute_term_in_expr(body, from, to)),
3175 },
3176 other => other.clone(),
3178 }
3179 }
3180
3181 fn substitute_in_term(
3183 &self,
3184 term: &ProofTerm,
3185 from: &ProofTerm,
3186 to: &ProofTerm,
3187 ) -> ProofTerm {
3188 if term == from {
3189 return to.clone();
3190 }
3191 match term {
3192 ProofTerm::Function(name, args) => {
3193 let new_args: Vec<_> = args
3194 .iter()
3195 .map(|arg| self.substitute_in_term(arg, from, to))
3196 .collect();
3197 ProofTerm::Function(name.clone(), new_args)
3198 }
3199 ProofTerm::Group(terms) => {
3200 let new_terms: Vec<_> = terms
3201 .iter()
3202 .map(|t| self.substitute_in_term(t, from, to))
3203 .collect();
3204 ProofTerm::Group(new_terms)
3205 }
3206 other => other.clone(),
3207 }
3208 }
3209
3210 fn try_structural_induction(
3224 &mut self,
3225 goal: &ProofGoal,
3226 depth: usize,
3227 ) -> ProofResult<Option<DerivationTree>> {
3228 if let Some((var_name, typename)) = self.find_typed_var(&goal.target) {
3230 if let Some(motive) = self.try_infer_motive(&goal.target, &var_name) {
3232 match typename.as_str() {
3233 "Nat" => {
3234 if let Ok(Some(proof)) =
3235 self.try_nat_induction_with_motive(goal, &var_name, &motive, depth)
3236 {
3237 return Ok(Some(proof));
3238 }
3239 }
3240 "List" => {
3241 }
3243 _ => {}
3244 }
3245 }
3246
3247 match typename.as_str() {
3249 "Nat" => self.try_nat_induction(goal, &var_name, depth),
3250 "List" => self.try_list_induction(goal, &var_name, depth),
3251 _ => Ok(None), }
3253 } else {
3254 Ok(None)
3255 }
3256 }
3257
3258 fn try_infer_motive(&self, goal: &ProofExpr, var_name: &str) -> Option<ProofExpr> {
3263 let motive_hole = ProofExpr::Hole("Motive".to_string());
3265 let pattern = ProofExpr::App(
3266 Box::new(motive_hole),
3267 Box::new(ProofExpr::Term(ProofTerm::BoundVarRef(var_name.to_string()))),
3268 );
3269
3270 let body = self.convert_typed_var_to_variable(goal, var_name);
3272
3273 match unify_pattern(&pattern, &body) {
3275 Ok(solution) => solution.get("Motive").cloned(),
3276 Err(_) => None,
3277 }
3278 }
3279
3280 fn convert_typed_var_to_variable(&self, expr: &ProofExpr, var_name: &str) -> ProofExpr {
3285 match expr {
3286 ProofExpr::TypedVar { name, .. } if name == var_name => {
3287 ProofExpr::Atom(name.clone())
3289 }
3290 ProofExpr::Identity(l, r) => ProofExpr::Identity(
3291 self.convert_typed_var_in_term(l, var_name),
3292 self.convert_typed_var_in_term(r, var_name),
3293 ),
3294 ProofExpr::Predicate { name, args, world } => ProofExpr::Predicate {
3295 name: name.clone(),
3296 args: args
3297 .iter()
3298 .map(|a| self.convert_typed_var_in_term(a, var_name))
3299 .collect(),
3300 world: world.clone(),
3301 },
3302 ProofExpr::And(l, r) => ProofExpr::And(
3303 Box::new(self.convert_typed_var_to_variable(l, var_name)),
3304 Box::new(self.convert_typed_var_to_variable(r, var_name)),
3305 ),
3306 ProofExpr::Or(l, r) => ProofExpr::Or(
3307 Box::new(self.convert_typed_var_to_variable(l, var_name)),
3308 Box::new(self.convert_typed_var_to_variable(r, var_name)),
3309 ),
3310 ProofExpr::Not(inner) => {
3311 ProofExpr::Not(Box::new(self.convert_typed_var_to_variable(inner, var_name)))
3312 }
3313 _ => expr.clone(),
3314 }
3315 }
3316
3317 fn convert_typed_var_in_term(&self, term: &ProofTerm, var_name: &str) -> ProofTerm {
3319 match term {
3320 ProofTerm::Variable(v) => {
3321 if v == var_name || v.starts_with(&format!("{}:", var_name)) {
3323 ProofTerm::Variable(var_name.to_string())
3324 } else {
3325 term.clone()
3326 }
3327 }
3328 ProofTerm::Function(name, args) => ProofTerm::Function(
3329 name.clone(),
3330 args.iter()
3331 .map(|a| self.convert_typed_var_in_term(a, var_name))
3332 .collect(),
3333 ),
3334 ProofTerm::Group(terms) => ProofTerm::Group(
3335 terms
3336 .iter()
3337 .map(|t| self.convert_typed_var_in_term(t, var_name))
3338 .collect(),
3339 ),
3340 _ => term.clone(),
3341 }
3342 }
3343
3344 fn try_nat_induction_with_motive(
3352 &mut self,
3353 goal: &ProofGoal,
3354 var_name: &str,
3355 motive: &ProofExpr,
3356 depth: usize,
3357 ) -> ProofResult<Option<DerivationTree>> {
3358 let zero_ctor = ProofExpr::Ctor {
3361 name: "Zero".into(),
3362 args: vec![],
3363 };
3364 let base_goal_expr = beta_reduce(&ProofExpr::App(
3365 Box::new(motive.clone()),
3366 Box::new(zero_ctor),
3367 ));
3368
3369 let base_goal = ProofGoal::with_context(base_goal_expr, goal.context.clone());
3370 let base_proof = match self.prove_goal(base_goal, depth + 1) {
3371 Ok(proof) => proof,
3372 Err(_) => return Ok(None),
3373 };
3374
3375 let fresh_k = self.fresh_var();
3377 let k_var = ProofExpr::Atom(fresh_k.clone());
3378
3379 let ih = beta_reduce(&ProofExpr::App(
3381 Box::new(motive.clone()),
3382 Box::new(k_var.clone()),
3383 ));
3384
3385 let succ_k = ProofExpr::Ctor {
3387 name: "Succ".into(),
3388 args: vec![k_var],
3389 };
3390 let step_goal_expr = beta_reduce(&ProofExpr::App(
3391 Box::new(motive.clone()),
3392 Box::new(succ_k),
3393 ));
3394
3395 let mut step_context = goal.context.clone();
3397 step_context.push(ih.clone());
3398
3399 let step_goal = ProofGoal::with_context(step_goal_expr, step_context);
3400 let step_proof = match self.try_step_case_with_equational_reasoning(&step_goal, &ih, depth)
3401 {
3402 Ok(proof) => proof,
3403 Err(_) => return Ok(None),
3404 };
3405
3406 Ok(Some(DerivationTree::new(
3407 goal.target.clone(),
3408 InferenceRule::StructuralInduction {
3409 variable: var_name.to_string(),
3410 ind_type: "Nat".to_string(),
3411 step_var: fresh_k,
3412 },
3413 vec![base_proof, step_proof],
3414 )))
3415 }
3416
3417 fn try_nat_induction(
3422 &mut self,
3423 goal: &ProofGoal,
3424 var_name: &str,
3425 depth: usize,
3426 ) -> ProofResult<Option<DerivationTree>> {
3427 let zero = ProofExpr::Ctor {
3429 name: "Zero".into(),
3430 args: vec![],
3431 };
3432
3433 let base_goal_expr = self.substitute_typed_var(&goal.target, var_name, &zero);
3435 let base_goal = ProofGoal::with_context(base_goal_expr, goal.context.clone());
3436
3437 let base_proof = match self.prove_goal(base_goal, depth + 1) {
3439 Ok(proof) => proof,
3440 Err(_) => return Ok(None), };
3442
3443 let fresh_k = self.fresh_var();
3445
3446 let k_var = ProofExpr::Atom(fresh_k.clone());
3448
3449 let succ_k = ProofExpr::Ctor {
3451 name: "Succ".into(),
3452 args: vec![k_var.clone()],
3453 };
3454
3455 let ih = self.substitute_typed_var(&goal.target, var_name, &k_var);
3457
3458 let step_goal_expr = self.substitute_typed_var(&goal.target, var_name, &succ_k);
3460
3461 let mut step_context = goal.context.clone();
3463 step_context.push(ih.clone());
3464
3465 let step_goal = ProofGoal::with_context(step_goal_expr, step_context);
3466
3467 let step_proof = match self.try_step_case_with_equational_reasoning(&step_goal, &ih, depth)
3469 {
3470 Ok(proof) => proof,
3471 Err(_) => return Ok(None), };
3473
3474 Ok(Some(DerivationTree::new(
3476 goal.target.clone(),
3477 InferenceRule::StructuralInduction {
3478 variable: var_name.to_string(),
3479 ind_type: "Nat".to_string(),
3480 step_var: fresh_k,
3481 },
3482 vec![base_proof, step_proof],
3483 )))
3484 }
3485
3486 fn try_list_induction(
3491 &mut self,
3492 goal: &ProofGoal,
3493 var_name: &str,
3494 depth: usize,
3495 ) -> ProofResult<Option<DerivationTree>> {
3496 let nil = ProofExpr::Ctor {
3498 name: "Nil".into(),
3499 args: vec![],
3500 };
3501
3502 let base_goal_expr = self.substitute_typed_var(&goal.target, var_name, &nil);
3504 let base_goal = ProofGoal::with_context(base_goal_expr, goal.context.clone());
3505
3506 let base_proof = match self.prove_goal(base_goal, depth + 1) {
3508 Ok(proof) => proof,
3509 Err(_) => return Ok(None),
3510 };
3511
3512 let fresh_h = self.fresh_var();
3514 let fresh_t = self.fresh_var();
3515
3516 let h_var = ProofExpr::Atom(fresh_h);
3517 let t_var = ProofExpr::Atom(fresh_t.clone());
3518
3519 let cons_ht = ProofExpr::Ctor {
3520 name: "Cons".into(),
3521 args: vec![h_var, t_var.clone()],
3522 };
3523
3524 let ih = self.substitute_typed_var(&goal.target, var_name, &t_var);
3526
3527 let step_goal_expr = self.substitute_typed_var(&goal.target, var_name, &cons_ht);
3529
3530 let mut step_context = goal.context.clone();
3531 step_context.push(ih.clone());
3532
3533 let step_goal = ProofGoal::with_context(step_goal_expr, step_context);
3534
3535 let step_proof = match self.try_step_case_with_equational_reasoning(&step_goal, &ih, depth)
3536 {
3537 Ok(proof) => proof,
3538 Err(_) => return Ok(None),
3539 };
3540
3541 Ok(Some(DerivationTree::new(
3542 goal.target.clone(),
3543 InferenceRule::StructuralInduction {
3544 variable: var_name.to_string(),
3545 ind_type: "List".to_string(),
3546 step_var: fresh_t,
3547 },
3548 vec![base_proof, step_proof],
3549 )))
3550 }
3551
3552 fn try_step_case_with_equational_reasoning(
3559 &mut self,
3560 goal: &ProofGoal,
3561 ih: &ProofExpr,
3562 depth: usize,
3563 ) -> ProofResult<DerivationTree> {
3564 if let Ok(proof) = self.prove_goal(goal.clone(), depth + 1) {
3566 return Ok(proof);
3567 }
3568
3569 if let ProofExpr::Identity(lhs, rhs) = &goal.target {
3571 if let Some(proof) = self.try_equational_proof(goal, lhs, rhs, ih, depth)? {
3573 return Ok(proof);
3574 }
3575 }
3576
3577 Err(ProofError::NoProofFound)
3578 }
3579
3580 fn try_equational_proof(
3588 &mut self,
3589 goal: &ProofGoal,
3590 lhs: &ProofTerm,
3591 rhs: &ProofTerm,
3592 ih: &ProofExpr,
3593 _depth: usize,
3594 ) -> ProofResult<Option<DerivationTree>> {
3595 let equations: Vec<ProofExpr> = self
3597 .knowledge_base
3598 .iter()
3599 .filter(|e| matches!(e, ProofExpr::Identity(_, _)))
3600 .cloned()
3601 .collect();
3602
3603 for eq_axiom in &equations {
3605 if let ProofExpr::Identity(_, _) = &eq_axiom {
3606 let renamed_axiom = self.rename_variables(&eq_axiom);
3608 if let ProofExpr::Identity(renamed_lhs, renamed_rhs) = renamed_axiom {
3609 if let Ok(subst) = unify_terms(&renamed_lhs, lhs) {
3613 let rewritten = self.apply_subst_to_term_with(&renamed_rhs, &subst);
3616
3617 if self.terms_equal_with_ih(&rewritten, rhs, ih) {
3619 let axiom_leaf =
3621 DerivationTree::leaf(eq_axiom.clone(), InferenceRule::PremiseMatch);
3622
3623 let ih_leaf =
3624 DerivationTree::leaf(ih.clone(), InferenceRule::PremiseMatch);
3625
3626 return Ok(Some(DerivationTree::new(
3627 goal.target.clone(),
3628 InferenceRule::PremiseMatch, vec![axiom_leaf, ih_leaf],
3630 )));
3631 }
3632 }
3633 }
3634 }
3635 }
3636
3637 Ok(None)
3638 }
3639
3640 fn terms_equal_with_ih(&self, t1: &ProofTerm, t2: &ProofTerm, ih: &ProofExpr) -> bool {
3642 if t1 == t2 {
3644 return true;
3645 }
3646
3647 if let ProofExpr::Identity(ih_lhs, ih_rhs) = ih {
3649 let t1_with_ih = self.rewrite_term_with_equation(t1, ih_lhs, ih_rhs);
3651 if &t1_with_ih == t2 {
3652 return true;
3653 }
3654
3655 let t2_with_ih = self.rewrite_term_with_equation(t2, ih_rhs, ih_lhs);
3657 if t1 == &t2_with_ih {
3658 return true;
3659 }
3660 }
3661
3662 false
3663 }
3664
3665 fn rewrite_term_with_equation(
3667 &self,
3668 term: &ProofTerm,
3669 from: &ProofTerm,
3670 to: &ProofTerm,
3671 ) -> ProofTerm {
3672 if term == from {
3674 return to.clone();
3675 }
3676
3677 match term {
3679 ProofTerm::Function(name, args) => {
3680 let new_args: Vec<ProofTerm> = args
3681 .iter()
3682 .map(|a| self.rewrite_term_with_equation(a, from, to))
3683 .collect();
3684 ProofTerm::Function(name.clone(), new_args)
3685 }
3686 ProofTerm::Group(terms) => {
3687 let new_terms: Vec<ProofTerm> = terms
3688 .iter()
3689 .map(|t| self.rewrite_term_with_equation(t, from, to))
3690 .collect();
3691 ProofTerm::Group(new_terms)
3692 }
3693 _ => term.clone(),
3694 }
3695 }
3696
3697 fn apply_subst_to_term_with(&self, term: &ProofTerm, subst: &Substitution) -> ProofTerm {
3699 match term {
3700 ProofTerm::Variable(v) => subst.get(v).cloned().unwrap_or_else(|| term.clone()),
3701 ProofTerm::Function(name, args) => ProofTerm::Function(
3702 name.clone(),
3703 args.iter()
3704 .map(|a| self.apply_subst_to_term_with(a, subst))
3705 .collect(),
3706 ),
3707 ProofTerm::Group(terms) => ProofTerm::Group(
3708 terms
3709 .iter()
3710 .map(|t| self.apply_subst_to_term_with(t, subst))
3711 .collect(),
3712 ),
3713 ProofTerm::Constant(_) => term.clone(),
3714 ProofTerm::BoundVarRef(_) => term.clone(),
3715 }
3716 }
3717
3718 fn find_typed_var(&self, expr: &ProofExpr) -> Option<(String, String)> {
3720 match expr {
3721 ProofExpr::TypedVar { name, typename } => Some((name.clone(), typename.clone())),
3722 ProofExpr::Identity(l, r) => {
3723 self.find_typed_var_in_term(l).or_else(|| self.find_typed_var_in_term(r))
3724 }
3725 ProofExpr::Predicate { args, .. } => {
3726 for arg in args {
3727 if let Some(tv) = self.find_typed_var_in_term(arg) {
3728 return Some(tv);
3729 }
3730 }
3731 None
3732 }
3733 ProofExpr::And(l, r)
3734 | ProofExpr::Or(l, r)
3735 | ProofExpr::Implies(l, r)
3736 | ProofExpr::Iff(l, r) => self.find_typed_var(l).or_else(|| self.find_typed_var(r)),
3737 ProofExpr::Not(inner) => self.find_typed_var(inner),
3738 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
3739 self.find_typed_var(body)
3740 }
3741 _ => None,
3742 }
3743 }
3744
3745 fn find_typed_var_in_term(&self, term: &ProofTerm) -> Option<(String, String)> {
3747 match term {
3748 ProofTerm::Variable(v) => {
3749 if v.contains(':') {
3753 let parts: Vec<&str> = v.splitn(2, ':').collect();
3754 if parts.len() == 2 {
3755 return Some((parts[0].to_string(), parts[1].to_string()));
3756 }
3757 }
3758 None
3759 }
3760 ProofTerm::Function(_, args) => {
3761 for arg in args {
3762 if let Some(tv) = self.find_typed_var_in_term(arg) {
3763 return Some(tv);
3764 }
3765 }
3766 None
3767 }
3768 ProofTerm::Group(terms) => {
3769 for t in terms {
3770 if let Some(tv) = self.find_typed_var_in_term(t) {
3771 return Some(tv);
3772 }
3773 }
3774 None
3775 }
3776 ProofTerm::Constant(_) => None,
3777 ProofTerm::BoundVarRef(_) => None, }
3779 }
3780
3781 fn substitute_typed_var(
3783 &self,
3784 expr: &ProofExpr,
3785 var_name: &str,
3786 replacement: &ProofExpr,
3787 ) -> ProofExpr {
3788 match expr {
3789 ProofExpr::TypedVar { name, .. } if name == var_name => replacement.clone(),
3790 ProofExpr::Identity(l, r) => {
3791 let new_l = self.substitute_typed_var_in_term(l, var_name, replacement);
3792 let new_r = self.substitute_typed_var_in_term(r, var_name, replacement);
3793 ProofExpr::Identity(new_l, new_r)
3794 }
3795 ProofExpr::Predicate { name, args, world } => {
3796 let new_args: Vec<ProofTerm> = args
3797 .iter()
3798 .map(|a| self.substitute_typed_var_in_term(a, var_name, replacement))
3799 .collect();
3800 ProofExpr::Predicate {
3801 name: name.clone(),
3802 args: new_args,
3803 world: world.clone(),
3804 }
3805 }
3806 ProofExpr::And(l, r) => ProofExpr::And(
3807 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3808 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3809 ),
3810 ProofExpr::Or(l, r) => ProofExpr::Or(
3811 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3812 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3813 ),
3814 ProofExpr::Implies(l, r) => ProofExpr::Implies(
3815 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3816 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3817 ),
3818 ProofExpr::Iff(l, r) => ProofExpr::Iff(
3819 Box::new(self.substitute_typed_var(l, var_name, replacement)),
3820 Box::new(self.substitute_typed_var(r, var_name, replacement)),
3821 ),
3822 ProofExpr::Not(inner) => {
3823 ProofExpr::Not(Box::new(self.substitute_typed_var(inner, var_name, replacement)))
3824 }
3825 ProofExpr::ForAll { variable, body } => ProofExpr::ForAll {
3826 variable: variable.clone(),
3827 body: Box::new(self.substitute_typed_var(body, var_name, replacement)),
3828 },
3829 ProofExpr::Exists { variable, body } => ProofExpr::Exists {
3830 variable: variable.clone(),
3831 body: Box::new(self.substitute_typed_var(body, var_name, replacement)),
3832 },
3833 _ => expr.clone(),
3834 }
3835 }
3836
3837 fn substitute_typed_var_in_term(
3839 &self,
3840 term: &ProofTerm,
3841 var_name: &str,
3842 replacement: &ProofExpr,
3843 ) -> ProofTerm {
3844 match term {
3845 ProofTerm::Variable(v) => {
3846 if v == var_name || v.starts_with(&format!("{}:", var_name)) {
3848 self.expr_to_term(replacement)
3849 } else {
3850 term.clone()
3851 }
3852 }
3853 ProofTerm::Function(name, args) => ProofTerm::Function(
3854 name.clone(),
3855 args.iter()
3856 .map(|a| self.substitute_typed_var_in_term(a, var_name, replacement))
3857 .collect(),
3858 ),
3859 ProofTerm::Group(terms) => ProofTerm::Group(
3860 terms
3861 .iter()
3862 .map(|t| self.substitute_typed_var_in_term(t, var_name, replacement))
3863 .collect(),
3864 ),
3865 ProofTerm::Constant(_) => term.clone(),
3866 ProofTerm::BoundVarRef(_) => term.clone(),
3867 }
3868 }
3869
3870 fn expr_to_term(&self, expr: &ProofExpr) -> ProofTerm {
3872 match expr {
3873 ProofExpr::Atom(s) => ProofTerm::Variable(s.clone()),
3874 ProofExpr::Ctor { name, args } => {
3875 ProofTerm::Function(name.clone(), args.iter().map(|a| self.expr_to_term(a)).collect())
3876 }
3877 ProofExpr::TypedVar { name, .. } => ProofTerm::Variable(name.clone()),
3878 _ => ProofTerm::Constant(format!("{}", expr)),
3879 }
3880 }
3881
3882 fn fresh_var(&mut self) -> String {
3888 self.var_counter += 1;
3889 format!("_G{}", self.var_counter)
3890 }
3891
3892 fn rename_variables(&mut self, expr: &ProofExpr) -> ProofExpr {
3894 let vars = self.collect_variables(expr);
3895 let mut subst = Substitution::new();
3896
3897 for var in vars {
3898 let fresh = self.fresh_var();
3899 subst.insert(var, ProofTerm::Variable(fresh));
3900 }
3901
3902 apply_subst_to_expr(expr, &subst)
3903 }
3904
3905 fn collect_variables(&self, expr: &ProofExpr) -> Vec<String> {
3907 let mut vars = Vec::new();
3908 self.collect_variables_recursive(expr, &mut vars);
3909 vars
3910 }
3911
3912 fn collect_variables_recursive(&self, expr: &ProofExpr, vars: &mut Vec<String>) {
3913 match expr {
3914 ProofExpr::Predicate { args, .. } => {
3915 for arg in args {
3916 self.collect_term_variables(arg, vars);
3917 }
3918 }
3919 ProofExpr::Identity(l, r) => {
3920 self.collect_term_variables(l, vars);
3921 self.collect_term_variables(r, vars);
3922 }
3923 ProofExpr::And(l, r)
3924 | ProofExpr::Or(l, r)
3925 | ProofExpr::Implies(l, r)
3926 | ProofExpr::Iff(l, r) => {
3927 self.collect_variables_recursive(l, vars);
3928 self.collect_variables_recursive(r, vars);
3929 }
3930 ProofExpr::Not(inner) => self.collect_variables_recursive(inner, vars),
3931 ProofExpr::ForAll { variable, body } | ProofExpr::Exists { variable, body } => {
3932 if !vars.contains(variable) {
3933 vars.push(variable.clone());
3934 }
3935 self.collect_variables_recursive(body, vars);
3936 }
3937 ProofExpr::Lambda { variable, body } => {
3938 if !vars.contains(variable) {
3939 vars.push(variable.clone());
3940 }
3941 self.collect_variables_recursive(body, vars);
3942 }
3943 ProofExpr::App(f, a) => {
3944 self.collect_variables_recursive(f, vars);
3945 self.collect_variables_recursive(a, vars);
3946 }
3947 ProofExpr::NeoEvent { roles, .. } => {
3948 for (_, term) in roles {
3949 self.collect_term_variables(term, vars);
3950 }
3951 }
3952 _ => {}
3953 }
3954 }
3955
3956 fn collect_term_variables(&self, term: &ProofTerm, vars: &mut Vec<String>) {
3957 match term {
3958 ProofTerm::Variable(v) => {
3959 if !vars.contains(v) {
3960 vars.push(v.clone());
3961 }
3962 }
3963 ProofTerm::Function(_, args) => {
3964 for arg in args {
3965 self.collect_term_variables(arg, vars);
3966 }
3967 }
3968 ProofTerm::Group(terms) => {
3969 for t in terms {
3970 self.collect_term_variables(t, vars);
3971 }
3972 }
3973 ProofTerm::Constant(_) => {}
3974 ProofTerm::BoundVarRef(_) => {} }
3976 }
3977
3978 fn collect_witnesses(&self) -> Vec<ProofTerm> {
3980 let mut witnesses = Vec::new();
3981
3982 for expr in &self.knowledge_base {
3983 self.collect_constants_from_expr(expr, &mut witnesses);
3984 }
3985
3986 witnesses
3987 }
3988
3989 fn collect_constants_from_expr(&self, expr: &ProofExpr, constants: &mut Vec<ProofTerm>) {
3990 match expr {
3991 ProofExpr::Predicate { args, .. } => {
3992 for arg in args {
3993 self.collect_constants_from_term(arg, constants);
3994 }
3995 }
3996 ProofExpr::Identity(l, r) => {
3997 self.collect_constants_from_term(l, constants);
3998 self.collect_constants_from_term(r, constants);
3999 }
4000 ProofExpr::And(l, r)
4001 | ProofExpr::Or(l, r)
4002 | ProofExpr::Implies(l, r)
4003 | ProofExpr::Iff(l, r) => {
4004 self.collect_constants_from_expr(l, constants);
4005 self.collect_constants_from_expr(r, constants);
4006 }
4007 ProofExpr::Not(inner) => self.collect_constants_from_expr(inner, constants),
4008 ProofExpr::ForAll { body, .. } | ProofExpr::Exists { body, .. } => {
4009 self.collect_constants_from_expr(body, constants);
4010 }
4011 ProofExpr::NeoEvent { roles, .. } => {
4012 for (_, term) in roles {
4013 self.collect_constants_from_term(term, constants);
4014 }
4015 }
4016 _ => {}
4017 }
4018 }
4019
4020 fn collect_constants_from_term(&self, term: &ProofTerm, constants: &mut Vec<ProofTerm>) {
4021 match term {
4022 ProofTerm::Constant(_) => {
4023 if !constants.contains(term) {
4024 constants.push(term.clone());
4025 }
4026 }
4027 ProofTerm::Function(_, args) => {
4028 if !constants.contains(term) {
4030 constants.push(term.clone());
4031 }
4032 for arg in args {
4033 self.collect_constants_from_term(arg, constants);
4034 }
4035 }
4036 ProofTerm::Group(terms) => {
4037 for t in terms {
4038 self.collect_constants_from_term(t, constants);
4039 }
4040 }
4041 ProofTerm::Variable(_) => {}
4042 ProofTerm::BoundVarRef(_) => {} }
4044 }
4045
4046 #[cfg(feature = "verification")]
4055 fn try_oracle_fallback(&self, goal: &ProofGoal) -> ProofResult<Option<DerivationTree>> {
4056 crate::oracle::try_oracle(goal, &self.knowledge_base)
4057 }
4058}
4059
4060fn extract_type_from_exists_body(body: &ProofExpr) -> Option<String> {
4070 match body {
4071 ProofExpr::TypedVar { typename, .. } => Some(typename.clone()),
4073
4074 ProofExpr::And(l, r) => {
4076 extract_type_from_exists_body(l).or_else(|| extract_type_from_exists_body(r))
4077 }
4078
4079 ProofExpr::Or(l, r) => {
4081 extract_type_from_exists_body(l).or_else(|| extract_type_from_exists_body(r))
4082 }
4083
4084 ProofExpr::Exists { body, .. } | ProofExpr::ForAll { body, .. } => {
4086 extract_type_from_exists_body(body)
4087 }
4088
4089 _ => None,
4091 }
4092}
4093
4094impl Default for BackwardChainer {
4095 fn default() -> Self {
4096 Self::new()
4097 }
4098}