1use crate::context::Context;
44use crate::omega;
45use crate::term::{Literal, Term, Universe};
46use crate::type_checker::substitute;
47
48pub fn normalize(ctx: &Context, term: &Term) -> Term {
53 let mut current = term.clone();
54 let mut fuel = 10000; loop {
57 if fuel == 0 {
58 return current;
60 }
61 fuel -= 1;
62
63 let reduced = reduce_step(ctx, ¤t);
64 if reduced == current {
65 return current;
66 }
67 current = reduced;
68 }
69}
70
71fn reduce_step(ctx: &Context, term: &Term) -> Term {
76 match term {
77 Term::Lit(_) => term.clone(),
79
80 Term::App(func, arg) => {
82 if let Some(result) = try_primitive_reduce(func, arg) {
84 return result;
85 }
86
87 if let Some(result) = try_reflection_reduce(ctx, func, arg) {
89 return result;
90 }
91
92 match func.as_ref() {
94 Term::Lambda { param, body, .. } => {
95 substitute(body, param, arg)
97 }
98 Term::Fix { name, body } => {
101 if is_constructor_form(ctx, arg) {
102 let fix_term = Term::Fix {
104 name: name.clone(),
105 body: body.clone(),
106 };
107 let unfolded = substitute(body, name, &fix_term);
108 Term::App(Box::new(unfolded), arg.clone())
109 } else {
110 let reduced_arg = reduce_step(ctx, arg);
112 if reduced_arg != **arg {
113 Term::App(func.clone(), Box::new(reduced_arg))
114 } else {
115 term.clone()
116 }
117 }
118 }
119 Term::App(_, _) => {
121 let reduced_func = reduce_step(ctx, func);
122 if reduced_func != **func {
123 Term::App(Box::new(reduced_func), arg.clone())
124 } else {
125 let reduced_arg = reduce_step(ctx, arg);
127 Term::App(func.clone(), Box::new(reduced_arg))
128 }
129 }
130 _ => {
132 let reduced_func = reduce_step(ctx, func);
133 if reduced_func != **func {
134 Term::App(Box::new(reduced_func), arg.clone())
135 } else {
136 let reduced_arg = reduce_step(ctx, arg);
138 Term::App(func.clone(), Box::new(reduced_arg))
139 }
140 }
141 }
142 }
143
144 Term::Match {
146 discriminant,
147 motive,
148 cases,
149 } => {
150 if let Some((ctor_idx, args)) = extract_constructor(ctx, discriminant) {
151 let case = &cases[ctor_idx];
153 let mut result = case.clone();
155 for arg in args {
156 result = Term::App(Box::new(result), Box::new(arg));
157 }
158 reduce_step(ctx, &result)
160 } else {
161 let reduced_disc = reduce_step(ctx, discriminant);
163 if reduced_disc != **discriminant {
164 Term::Match {
165 discriminant: Box::new(reduced_disc),
166 motive: motive.clone(),
167 cases: cases.clone(),
168 }
169 } else {
170 term.clone()
171 }
172 }
173 }
174
175 Term::Lambda {
177 param,
178 param_type,
179 body,
180 } => {
181 let reduced_param_type = reduce_step(ctx, param_type);
182 let reduced_body = reduce_step(ctx, body);
183 if reduced_param_type != **param_type || reduced_body != **body {
184 Term::Lambda {
185 param: param.clone(),
186 param_type: Box::new(reduced_param_type),
187 body: Box::new(reduced_body),
188 }
189 } else {
190 term.clone()
191 }
192 }
193
194 Term::Pi {
196 param,
197 param_type,
198 body_type,
199 } => {
200 let reduced_param_type = reduce_step(ctx, param_type);
201 let reduced_body_type = reduce_step(ctx, body_type);
202 if reduced_param_type != **param_type || reduced_body_type != **body_type {
203 Term::Pi {
204 param: param.clone(),
205 param_type: Box::new(reduced_param_type),
206 body_type: Box::new(reduced_body_type),
207 }
208 } else {
209 term.clone()
210 }
211 }
212
213 Term::Fix { name, body } => {
215 let reduced_body = reduce_step(ctx, body);
216 if reduced_body != **body {
217 Term::Fix {
218 name: name.clone(),
219 body: Box::new(reduced_body),
220 }
221 } else {
222 term.clone()
223 }
224 }
225
226 Term::Sort(_) | Term::Var(_) | Term::Hole => term.clone(),
228
229 Term::Global(name) => {
231 if let Some(body) = ctx.get_definition_body(name) {
232 body.clone()
234 } else {
235 term.clone()
237 }
238 }
239 }
240}
241
242fn is_constructor_form(ctx: &Context, term: &Term) -> bool {
244 extract_constructor(ctx, term).is_some()
245}
246
247fn extract_constructor(ctx: &Context, term: &Term) -> Option<(usize, Vec<Term>)> {
254 let mut args = Vec::new();
255 let mut current = term;
256
257 while let Term::App(func, arg) = current {
259 args.push((**arg).clone());
260 current = func;
261 }
262 args.reverse();
263
264 if let Term::Global(name) = current {
266 if let Some(inductive) = ctx.constructor_inductive(name) {
267 let ctors = ctx.get_constructors(inductive);
268 for (idx, (ctor_name, ctor_type)) in ctors.iter().enumerate() {
269 if *ctor_name == name {
270 let num_type_params = count_type_params(ctor_type);
272
273 let value_args = if num_type_params < args.len() {
275 args[num_type_params..].to_vec()
276 } else {
277 vec![]
278 };
279
280 return Some((idx, value_args));
281 }
282 }
283 }
284 }
285 None
286}
287
288fn count_type_params(ty: &Term) -> usize {
293 let mut count = 0;
294 let mut current = ty;
295
296 while let Term::Pi { param_type, body_type, .. } = current {
297 if is_sort(param_type) {
298 count += 1;
299 current = body_type;
300 } else {
301 break;
302 }
303 }
304
305 count
306}
307
308fn is_sort(term: &Term) -> bool {
310 matches!(term, Term::Sort(_))
311}
312
313fn try_primitive_reduce(func: &Term, arg: &Term) -> Option<Term> {
318 if let Term::App(op_term, x) = func {
320 if let Term::Global(op_name) = op_term.as_ref() {
321 if let (Term::Lit(Literal::Int(x_val)), Term::Lit(Literal::Int(y_val))) =
322 (x.as_ref(), arg)
323 {
324 let result = match op_name.as_str() {
325 "add" => x_val.checked_add(*y_val)?,
326 "sub" => x_val.checked_sub(*y_val)?,
327 "mul" => x_val.checked_mul(*y_val)?,
328 "div" => x_val.checked_div(*y_val)?,
329 "mod" => x_val.checked_rem(*y_val)?,
330 _ => return None,
331 };
332 return Some(Term::Lit(Literal::Int(result)));
333 }
334 }
335 }
336 None
337}
338
339fn try_reflection_reduce(ctx: &Context, func: &Term, arg: &Term) -> Option<Term> {
350 if let Term::Global(op_name) = func {
352 match op_name.as_str() {
353 "syn_size" => {
354 let norm_arg = normalize(ctx, arg);
356 return try_syn_size_reduce(ctx, &norm_arg);
357 }
358 "syn_max_var" => {
359 let norm_arg = normalize(ctx, arg);
361 return try_syn_max_var_reduce(ctx, &norm_arg, 0);
362 }
363 "syn_step" => {
364 let norm_arg = normalize(ctx, arg);
366 return try_syn_step_reduce(ctx, &norm_arg);
367 }
368 "syn_quote" => {
369 let norm_arg = normalize(ctx, arg);
371 return try_syn_quote_reduce(ctx, &norm_arg);
372 }
373 "syn_diag" => {
374 let norm_arg = normalize(ctx, arg);
376 return try_syn_diag_reduce(ctx, &norm_arg);
377 }
378 "concludes" => {
379 let norm_arg = normalize(ctx, arg);
381 return try_concludes_reduce(ctx, &norm_arg);
382 }
383 "try_refl" => {
384 let norm_arg = normalize(ctx, arg);
386 return try_try_refl_reduce(ctx, &norm_arg);
387 }
388 "tact_fail" => {
389 return Some(make_error_derivation());
391 }
392 "try_compute" => {
393 let norm_arg = normalize(ctx, arg);
396 return Some(Term::App(
397 Box::new(Term::Global("DCompute".to_string())),
398 Box::new(norm_arg),
399 ));
400 }
401 "try_ring" => {
402 let norm_arg = normalize(ctx, arg);
404 return try_try_ring_reduce(ctx, &norm_arg);
405 }
406 "try_lia" => {
407 let norm_arg = normalize(ctx, arg);
409 return try_try_lia_reduce(ctx, &norm_arg);
410 }
411 "try_cc" => {
412 let norm_arg = normalize(ctx, arg);
414 return try_try_cc_reduce(ctx, &norm_arg);
415 }
416 "try_simp" => {
417 let norm_arg = normalize(ctx, arg);
419 return try_try_simp_reduce(ctx, &norm_arg);
420 }
421 "try_omega" => {
422 let norm_arg = normalize(ctx, arg);
424 return try_try_omega_reduce(ctx, &norm_arg);
425 }
426 "try_auto" => {
427 let norm_arg = normalize(ctx, arg);
429 return try_try_auto_reduce(ctx, &norm_arg);
430 }
431 "try_bitblast" => {
432 let norm_arg = normalize(ctx, arg);
434 return try_try_bitblast_reduce(ctx, &norm_arg);
435 }
436 "try_tabulate" => {
437 let norm_arg = normalize(ctx, arg);
439 return try_try_tabulate_reduce(ctx, &norm_arg);
440 }
441 "try_hw_auto" => {
442 let norm_arg = normalize(ctx, arg);
444 return try_try_hw_auto_reduce(ctx, &norm_arg);
445 }
446 "try_inversion" => {
447 let norm_arg = normalize(ctx, arg);
449 return try_try_inversion_reduce(ctx, &norm_arg);
450 }
451 "induction_num_cases" => {
452 let norm_arg = normalize(ctx, arg);
454 return try_induction_num_cases_reduce(ctx, &norm_arg);
455 }
456 _ => {}
457 }
458 }
459
460 if let Term::App(partial2, cutoff) = func {
467 if let Term::App(partial1, amount) = partial2.as_ref() {
468 if let Term::Global(op_name) = partial1.as_ref() {
469 if op_name == "syn_lift" {
470 if let (Term::Lit(Literal::Int(amt)), Term::Lit(Literal::Int(cut))) =
471 (amount.as_ref(), cutoff.as_ref())
472 {
473 let norm_term = normalize(ctx, arg);
474 return try_syn_lift_reduce(ctx, *amt, *cut, &norm_term);
475 }
476 }
477 }
478 }
479 }
480
481 if let Term::App(partial2, index) = func {
484 if let Term::App(partial1, replacement) = partial2.as_ref() {
485 if let Term::Global(op_name) = partial1.as_ref() {
486 if op_name == "syn_subst" {
487 if let Term::Lit(Literal::Int(idx)) = index.as_ref() {
488 let norm_replacement = normalize(ctx, replacement);
489 let norm_term = normalize(ctx, arg);
490 return try_syn_subst_reduce(ctx, &norm_replacement, *idx, &norm_term);
491 }
492 }
493 }
494 }
495 }
496
497 if let Term::App(partial1, body) = func {
500 if let Term::Global(op_name) = partial1.as_ref() {
501 if op_name == "syn_beta" {
502 let norm_body = normalize(ctx, body);
503 let norm_arg = normalize(ctx, arg);
504 return try_syn_beta_reduce(ctx, &norm_body, &norm_arg);
505 }
506 }
507 }
508
509 if let Term::App(partial1, context) = func {
513 if let Term::Global(op_name) = partial1.as_ref() {
514 if op_name == "try_cong" {
515 let norm_context = normalize(ctx, context);
516 let norm_proof = normalize(ctx, arg);
517 return Some(Term::App(
518 Box::new(Term::App(
519 Box::new(Term::Global("DCong".to_string())),
520 Box::new(norm_context),
521 )),
522 Box::new(norm_proof),
523 ));
524 }
525 }
526 }
527
528 if let Term::App(partial1, eq_proof) = func {
532 if let Term::Global(op_name) = partial1.as_ref() {
533 if op_name == "try_rewrite" {
534 let norm_eq_proof = normalize(ctx, eq_proof);
535 let norm_goal = normalize(ctx, arg);
536 return try_try_rewrite_reduce(ctx, &norm_eq_proof, &norm_goal, false);
537 }
538 if op_name == "try_rewrite_rev" {
539 let norm_eq_proof = normalize(ctx, eq_proof);
540 let norm_goal = normalize(ctx, arg);
541 return try_try_rewrite_reduce(ctx, &norm_eq_proof, &norm_goal, true);
542 }
543 }
544 }
545
546 if let Term::App(partial1, fuel_term) = func {
549 if let Term::Global(op_name) = partial1.as_ref() {
550 if op_name == "syn_eval" {
551 if let Term::Lit(Literal::Int(fuel)) = fuel_term.as_ref() {
552 let norm_term = normalize(ctx, arg);
553 return try_syn_eval_reduce(ctx, *fuel, &norm_term);
554 }
555 }
556 }
557 }
558
559 if let Term::App(partial1, ind_type) = func {
562 if let Term::Global(op_name) = partial1.as_ref() {
563 if op_name == "induction_base_goal" {
564 let norm_ind_type = normalize(ctx, ind_type);
565 let norm_motive = normalize(ctx, arg);
566 return try_induction_base_goal_reduce(ctx, &norm_ind_type, &norm_motive);
567 }
568 }
569 }
570
571 if let Term::App(partial1, t2) = func {
575 if let Term::App(combinator, t1) = partial1.as_ref() {
576 if let Term::Global(name) = combinator.as_ref() {
577 if name == "tact_orelse" {
578 return try_tact_orelse_reduce(ctx, t1, t2, arg);
579 }
580 if name == "tact_then" {
582 return try_tact_then_reduce(ctx, t1, t2, arg);
583 }
584 }
585 }
586 }
587
588 if let Term::App(combinator, t) = func {
591 if let Term::Global(name) = combinator.as_ref() {
592 if name == "tact_try" {
593 return try_tact_try_reduce(ctx, t, arg);
594 }
595 if name == "tact_repeat" {
597 return try_tact_repeat_reduce(ctx, t, arg);
598 }
599 if name == "tact_solve" {
601 return try_tact_solve_reduce(ctx, t, arg);
602 }
603 if name == "tact_first" {
605 return try_tact_first_reduce(ctx, t, arg);
606 }
607 }
608 }
609
610 if let Term::App(partial1, motive) = func {
614 if let Term::App(combinator, ind_type) = partial1.as_ref() {
615 if let Term::Global(name) = combinator.as_ref() {
616 if name == "induction_step_goal" {
617 let norm_ind_type = normalize(ctx, ind_type);
618 let norm_motive = normalize(ctx, motive);
619 let norm_idx = normalize(ctx, arg);
620 return try_induction_step_goal_reduce(ctx, &norm_ind_type, &norm_motive, &norm_idx);
621 }
622 }
623 }
624 }
625
626 if let Term::App(partial1, motive) = func {
630 if let Term::App(combinator, ind_type) = partial1.as_ref() {
631 if let Term::Global(name) = combinator.as_ref() {
632 if name == "try_induction" {
633 let norm_ind_type = normalize(ctx, ind_type);
634 let norm_motive = normalize(ctx, motive);
635 let norm_cases = normalize(ctx, arg);
636 return try_try_induction_reduce(ctx, &norm_ind_type, &norm_motive, &norm_cases);
637 }
638 }
639 }
640 }
641
642 if let Term::App(partial1, motive) = func {
646 if let Term::App(combinator, ind_type) = partial1.as_ref() {
647 if let Term::Global(name) = combinator.as_ref() {
648 if name == "try_destruct" {
649 let norm_ind_type = normalize(ctx, ind_type);
650 let norm_motive = normalize(ctx, motive);
651 let norm_cases = normalize(ctx, arg);
652 return try_try_destruct_reduce(ctx, &norm_ind_type, &norm_motive, &norm_cases);
653 }
654 }
655 }
656 }
657
658 if let Term::App(partial1, hyp_proof) = func {
662 if let Term::App(combinator, hyp_name) = partial1.as_ref() {
663 if let Term::Global(name) = combinator.as_ref() {
664 if name == "try_apply" {
665 let norm_hyp_name = normalize(ctx, hyp_name);
666 let norm_hyp_proof = normalize(ctx, hyp_proof);
667 let norm_goal = normalize(ctx, arg);
668 return try_try_apply_reduce(ctx, &norm_hyp_name, &norm_hyp_proof, &norm_goal);
669 }
670 }
671 }
672 }
673
674 None
675}
676
677fn try_syn_size_reduce(ctx: &Context, term: &Term) -> Option<Term> {
686 if let Term::App(ctor_term, _inner_arg) = term {
692 if let Term::Global(ctor_name) = ctor_term.as_ref() {
693 match ctor_name.as_str() {
694 "SVar" | "SGlobal" | "SSort" | "SLit" | "SName" => {
695 return Some(Term::Lit(Literal::Int(1)));
696 }
697 _ => {}
698 }
699 }
700
701 if let Term::App(inner, a) = ctor_term.as_ref() {
703 if let Term::Global(ctor_name) = inner.as_ref() {
704 match ctor_name.as_str() {
705 "SApp" | "SLam" | "SPi" => {
706 let a_size = try_syn_size_reduce(ctx, a)?;
708 let b_size = try_syn_size_reduce(ctx, _inner_arg)?;
709
710 if let (Term::Lit(Literal::Int(a_n)), Term::Lit(Literal::Int(b_n))) =
711 (a_size, b_size)
712 {
713 return Some(Term::Lit(Literal::Int(1 + a_n + b_n)));
714 }
715 }
716 _ => {}
717 }
718 }
719 }
720 }
721
722 None
723}
724
725fn try_syn_max_var_reduce(ctx: &Context, term: &Term, depth: i64) -> Option<Term> {
735 if let Term::App(ctor_term, inner_arg) = term {
737 if let Term::Global(ctor_name) = ctor_term.as_ref() {
738 match ctor_name.as_str() {
739 "SVar" => {
740 if let Term::Lit(Literal::Int(k)) = inner_arg.as_ref() {
742 if *k >= depth {
743 return Some(Term::Lit(Literal::Int(*k - depth)));
745 } else {
746 return Some(Term::Lit(Literal::Int(-1)));
748 }
749 }
750 }
751 "SGlobal" | "SSort" | "SLit" | "SName" => {
752 return Some(Term::Lit(Literal::Int(-1)));
754 }
755 _ => {}
756 }
757 }
758
759 if let Term::App(inner, a) = ctor_term.as_ref() {
761 if let Term::Global(ctor_name) = inner.as_ref() {
762 match ctor_name.as_str() {
763 "SApp" => {
764 let a_max = try_syn_max_var_reduce(ctx, a, depth)?;
766 let b_max = try_syn_max_var_reduce(ctx, inner_arg, depth)?;
767
768 if let (Term::Lit(Literal::Int(a_n)), Term::Lit(Literal::Int(b_n))) =
769 (a_max, b_max)
770 {
771 return Some(Term::Lit(Literal::Int(a_n.max(b_n))));
772 }
773 }
774 "SLam" | "SPi" => {
775 let a_max = try_syn_max_var_reduce(ctx, a, depth)?;
778 let b_max = try_syn_max_var_reduce(ctx, inner_arg, depth + 1)?;
779
780 if let (Term::Lit(Literal::Int(a_n)), Term::Lit(Literal::Int(b_n))) =
781 (a_max, b_max)
782 {
783 return Some(Term::Lit(Literal::Int(a_n.max(b_n))));
784 }
785 }
786 _ => {}
787 }
788 }
789 }
790 }
791
792 None
793}
794
795fn try_syn_lift_reduce(ctx: &Context, amount: i64, cutoff: i64, term: &Term) -> Option<Term> {
805 if let Term::App(ctor_term, inner_arg) = term {
807 if let Term::Global(ctor_name) = ctor_term.as_ref() {
808 match ctor_name.as_str() {
809 "SVar" => {
810 if let Term::Lit(Literal::Int(k)) = inner_arg.as_ref() {
811 if *k >= cutoff {
812 return Some(Term::App(
814 Box::new(Term::Global("SVar".to_string())),
815 Box::new(Term::Lit(Literal::Int(*k + amount))),
816 ));
817 } else {
818 return Some(term.clone());
820 }
821 }
822 }
823 "SGlobal" | "SSort" | "SLit" | "SName" => {
824 return Some(term.clone());
826 }
827 _ => {}
828 }
829 }
830
831 if let Term::App(inner, a) = ctor_term.as_ref() {
833 if let Term::Global(ctor_name) = inner.as_ref() {
834 match ctor_name.as_str() {
835 "SApp" => {
836 let a_lifted = try_syn_lift_reduce(ctx, amount, cutoff, a)?;
838 let b_lifted = try_syn_lift_reduce(ctx, amount, cutoff, inner_arg)?;
839 return Some(Term::App(
840 Box::new(Term::App(
841 Box::new(Term::Global("SApp".to_string())),
842 Box::new(a_lifted),
843 )),
844 Box::new(b_lifted),
845 ));
846 }
847 "SLam" | "SPi" => {
848 let param_lifted = try_syn_lift_reduce(ctx, amount, cutoff, a)?;
850 let body_lifted =
851 try_syn_lift_reduce(ctx, amount, cutoff + 1, inner_arg)?;
852 return Some(Term::App(
853 Box::new(Term::App(
854 Box::new(Term::Global(ctor_name.clone())),
855 Box::new(param_lifted),
856 )),
857 Box::new(body_lifted),
858 ));
859 }
860 _ => {}
861 }
862 }
863 }
864 }
865
866 None
867}
868
869fn try_syn_subst_reduce(
876 ctx: &Context,
877 replacement: &Term,
878 index: i64,
879 term: &Term,
880) -> Option<Term> {
881 if let Term::App(ctor_term, inner_arg) = term {
883 if let Term::Global(ctor_name) = ctor_term.as_ref() {
884 match ctor_name.as_str() {
885 "SVar" => {
886 if let Term::Lit(Literal::Int(k)) = inner_arg.as_ref() {
887 if *k == index {
888 return Some(replacement.clone());
890 } else {
891 return Some(term.clone());
893 }
894 }
895 }
896 "SGlobal" | "SSort" | "SLit" | "SName" => {
897 return Some(term.clone());
899 }
900 _ => {}
901 }
902 }
903
904 if let Term::App(inner, a) = ctor_term.as_ref() {
906 if let Term::Global(ctor_name) = inner.as_ref() {
907 match ctor_name.as_str() {
908 "SApp" => {
909 let a_subst = try_syn_subst_reduce(ctx, replacement, index, a)?;
911 let b_subst = try_syn_subst_reduce(ctx, replacement, index, inner_arg)?;
912 return Some(Term::App(
913 Box::new(Term::App(
914 Box::new(Term::Global("SApp".to_string())),
915 Box::new(a_subst),
916 )),
917 Box::new(b_subst),
918 ));
919 }
920 "SLam" | "SPi" => {
921 let param_subst = try_syn_subst_reduce(ctx, replacement, index, a)?;
924
925 let lifted_replacement = try_syn_lift_reduce(ctx, 1, 0, replacement)?;
927 let body_subst = try_syn_subst_reduce(
928 ctx,
929 &lifted_replacement,
930 index + 1,
931 inner_arg,
932 )?;
933
934 return Some(Term::App(
935 Box::new(Term::App(
936 Box::new(Term::Global(ctor_name.clone())),
937 Box::new(param_subst),
938 )),
939 Box::new(body_subst),
940 ));
941 }
942 _ => {}
943 }
944 }
945 }
946 }
947
948 None
949}
950
951fn try_syn_beta_reduce(ctx: &Context, body: &Term, arg: &Term) -> Option<Term> {
959 try_syn_subst_reduce(ctx, arg, 0, body)
961}
962
963fn try_syn_arith_reduce(func: &Term, arg: &Term) -> Option<Term> {
968 if let Term::App(inner_ctor, n_term) = func {
971 if let Term::App(sapp_ctor, op_term) = inner_ctor.as_ref() {
972 if let Term::Global(ctor_name) = sapp_ctor.as_ref() {
974 if ctor_name != "SApp" {
975 return None;
976 }
977 } else {
978 return None;
979 }
980
981 let op = if let Term::App(sname_ctor, op_str) = op_term.as_ref() {
983 if let Term::Global(name) = sname_ctor.as_ref() {
984 if name == "SName" {
985 if let Term::Lit(Literal::Text(op)) = op_str.as_ref() {
986 op.clone()
987 } else {
988 return None;
989 }
990 } else {
991 return None;
992 }
993 } else {
994 return None;
995 }
996 } else {
997 return None;
998 };
999
1000 let n = if let Term::App(slit_ctor, n_val) = n_term.as_ref() {
1002 if let Term::Global(name) = slit_ctor.as_ref() {
1003 if name == "SLit" {
1004 if let Term::Lit(Literal::Int(n)) = n_val.as_ref() {
1005 *n
1006 } else {
1007 return None;
1008 }
1009 } else {
1010 return None;
1011 }
1012 } else {
1013 return None;
1014 }
1015 } else {
1016 return None;
1017 };
1018
1019 let m = if let Term::App(slit_ctor, m_val) = arg {
1021 if let Term::Global(name) = slit_ctor.as_ref() {
1022 if name == "SLit" {
1023 if let Term::Lit(Literal::Int(m)) = m_val.as_ref() {
1024 *m
1025 } else {
1026 return None;
1027 }
1028 } else {
1029 return None;
1030 }
1031 } else {
1032 return None;
1033 }
1034 } else {
1035 return None;
1036 };
1037
1038 let result = match op.as_str() {
1040 "add" => n.checked_add(m),
1041 "sub" => n.checked_sub(m),
1042 "mul" => n.checked_mul(m),
1043 "div" => {
1044 if m == 0 {
1045 return None; }
1047 n.checked_div(m)
1048 }
1049 "mod" => {
1050 if m == 0 {
1051 return None; }
1053 n.checked_rem(m)
1054 }
1055 _ => None,
1056 };
1057
1058 if let Some(r) = result {
1060 return Some(Term::App(
1061 Box::new(Term::Global("SLit".to_string())),
1062 Box::new(Term::Lit(Literal::Int(r))),
1063 ));
1064 }
1065 }
1066 }
1067
1068 None
1069}
1070
1071fn try_syn_step_reduce(ctx: &Context, term: &Term) -> Option<Term> {
1078 if let Term::App(ctor_term, arg) = term {
1080 if let Term::App(inner, func) = ctor_term.as_ref() {
1081 if let Term::Global(ctor_name) = inner.as_ref() {
1082 if ctor_name == "SApp" {
1083 if let Some(result) = try_syn_arith_reduce(func.as_ref(), arg.as_ref()) {
1086 return Some(result);
1087 }
1088
1089 if let Term::App(lam_inner, body) = func.as_ref() {
1091 if let Term::App(lam_ctor, _param_type) = lam_inner.as_ref() {
1092 if let Term::Global(lam_name) = lam_ctor.as_ref() {
1093 if lam_name == "SLam" {
1094 return try_syn_beta_reduce(ctx, body.as_ref(), arg.as_ref());
1096 }
1097 }
1098 }
1099 }
1100
1101 {
1108 let full_app = term; if let Some(kernel_term) = syntax_to_term(full_app) {
1110 let normalized = normalize(ctx, &kernel_term);
1111 if normalized != kernel_term {
1112 if let Some(result_syntax) = term_to_syntax(&normalized) {
1113 return Some(result_syntax);
1114 }
1115 }
1116 }
1117 }
1118
1119 if let Some(stepped_func) = try_syn_step_reduce(ctx, func.as_ref()) {
1121 if &stepped_func != func.as_ref() {
1123 return Some(Term::App(
1125 Box::new(Term::App(
1126 Box::new(Term::Global("SApp".to_string())),
1127 Box::new(stepped_func),
1128 )),
1129 Box::new(arg.as_ref().clone()),
1130 ));
1131 }
1132 }
1133
1134 if let Some(stepped_arg) = try_syn_step_reduce(ctx, arg.as_ref()) {
1136 if &stepped_arg != arg.as_ref() {
1137 return Some(Term::App(
1139 Box::new(Term::App(
1140 Box::new(Term::Global("SApp".to_string())),
1141 Box::new(func.as_ref().clone()),
1142 )),
1143 Box::new(stepped_arg),
1144 ));
1145 }
1146 }
1147
1148 return Some(term.clone());
1150 }
1151 }
1152 }
1153 }
1154
1155 Some(term.clone())
1158}
1159
1160fn try_syn_eval_reduce(ctx: &Context, fuel: i64, term: &Term) -> Option<Term> {
1170 if fuel <= 0 {
1171 return Some(term.clone());
1172 }
1173
1174 let stepped = try_syn_step_reduce(ctx, term)?;
1176
1177 if &stepped == term {
1179 return Some(term.clone());
1180 }
1181
1182 try_syn_eval_reduce(ctx, fuel - 1, &stepped)
1184}
1185
1186#[allow(dead_code)]
1202fn try_syn_quote_reduce(ctx: &Context, term: &Term) -> Option<Term> {
1203 fn sname_app(name: &str, arg: Term) -> Term {
1205 Term::App(
1206 Box::new(Term::App(
1207 Box::new(Term::Global("SApp".to_string())),
1208 Box::new(Term::App(
1209 Box::new(Term::Global("SName".to_string())),
1210 Box::new(Term::Lit(Literal::Text(name.to_string()))),
1211 )),
1212 )),
1213 Box::new(arg),
1214 )
1215 }
1216
1217 fn slit(n: i64) -> Term {
1219 Term::App(
1220 Box::new(Term::Global("SLit".to_string())),
1221 Box::new(Term::Lit(Literal::Int(n))),
1222 )
1223 }
1224
1225 fn sname(s: &str) -> Term {
1227 Term::App(
1228 Box::new(Term::Global("SName".to_string())),
1229 Box::new(Term::Lit(Literal::Text(s.to_string()))),
1230 )
1231 }
1232
1233 fn sname_app2(name: &str, a: Term, b: Term) -> Term {
1235 Term::App(
1236 Box::new(Term::App(
1237 Box::new(Term::Global("SApp".to_string())),
1238 Box::new(sname_app(name, a)),
1239 )),
1240 Box::new(b),
1241 )
1242 }
1243
1244 if let Term::App(ctor_term, inner_arg) = term {
1246 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1247 match ctor_name.as_str() {
1248 "SVar" => {
1249 if let Term::Lit(Literal::Int(n)) = inner_arg.as_ref() {
1250 return Some(sname_app("SVar", slit(*n)));
1251 }
1252 }
1253 "SGlobal" => {
1254 if let Term::Lit(Literal::Int(n)) = inner_arg.as_ref() {
1255 return Some(sname_app("SGlobal", slit(*n)));
1256 }
1257 }
1258 "SSort" => {
1259 let quoted_univ = quote_univ(inner_arg)?;
1261 return Some(sname_app("SSort", quoted_univ));
1262 }
1263 "SLit" => {
1264 if let Term::Lit(Literal::Int(n)) = inner_arg.as_ref() {
1265 return Some(sname_app("SLit", slit(*n)));
1266 }
1267 }
1268 "SName" => {
1269 return Some(term.clone());
1271 }
1272 _ => {}
1273 }
1274 }
1275
1276 if let Term::App(inner, a) = ctor_term.as_ref() {
1278 if let Term::Global(ctor_name) = inner.as_ref() {
1279 match ctor_name.as_str() {
1280 "SApp" | "SLam" | "SPi" => {
1281 let quoted_a = try_syn_quote_reduce(ctx, a)?;
1282 let quoted_b = try_syn_quote_reduce(ctx, inner_arg)?;
1283 return Some(sname_app2(ctor_name, quoted_a, quoted_b));
1284 }
1285 _ => {}
1286 }
1287 }
1288 }
1289 }
1290
1291 None
1292}
1293
1294fn quote_univ(term: &Term) -> Option<Term> {
1299 fn sname(s: &str) -> Term {
1300 Term::App(
1301 Box::new(Term::Global("SName".to_string())),
1302 Box::new(Term::Lit(Literal::Text(s.to_string()))),
1303 )
1304 }
1305
1306 fn slit(n: i64) -> Term {
1307 Term::App(
1308 Box::new(Term::Global("SLit".to_string())),
1309 Box::new(Term::Lit(Literal::Int(n))),
1310 )
1311 }
1312
1313 fn sname_app(name: &str, arg: Term) -> Term {
1314 Term::App(
1315 Box::new(Term::App(
1316 Box::new(Term::Global("SApp".to_string())),
1317 Box::new(sname(name)),
1318 )),
1319 Box::new(arg),
1320 )
1321 }
1322
1323 if let Term::Global(name) = term {
1324 if name == "UProp" {
1325 return Some(sname("UProp"));
1326 }
1327 }
1328
1329 if let Term::App(ctor, arg) = term {
1330 if let Term::Global(name) = ctor.as_ref() {
1331 if name == "UType" {
1332 if let Term::Lit(Literal::Int(n)) = arg.as_ref() {
1333 return Some(sname_app("UType", slit(*n)));
1334 }
1335 }
1336 }
1337 }
1338
1339 None
1340}
1341
1342fn try_syn_diag_reduce(ctx: &Context, term: &Term) -> Option<Term> {
1351 let quoted = try_syn_quote_reduce(ctx, term)?;
1353
1354 try_syn_subst_reduce(ctx, "ed, 0, term)
1356}
1357
1358fn try_concludes_reduce(ctx: &Context, deriv: &Term) -> Option<Term> {
1371 if let Term::App(ctor_term, p) = deriv {
1373 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1374 if ctor_name == "DAxiom" {
1375 return Some(p.as_ref().clone());
1376 }
1377 if ctor_name == "DUnivIntro" {
1378 let inner_conc = try_concludes_reduce(ctx, p)?;
1380 let lifted = try_syn_lift_reduce(ctx, 1, 0, &inner_conc)?;
1382 return Some(make_forall_syntax(&lifted));
1383 }
1384 if ctor_name == "DCompute" {
1385 return try_dcompute_conclude(ctx, p);
1387 }
1388 if ctor_name == "DRingSolve" {
1389 return try_dring_solve_conclude(ctx, p);
1391 }
1392 if ctor_name == "DLiaSolve" {
1393 return try_dlia_solve_conclude(ctx, p);
1395 }
1396 if ctor_name == "DccSolve" {
1397 return try_dcc_solve_conclude(ctx, p);
1399 }
1400 if ctor_name == "DSimpSolve" {
1401 return try_dsimp_solve_conclude(ctx, p);
1403 }
1404 if ctor_name == "DOmegaSolve" {
1405 return try_domega_solve_conclude(ctx, p);
1407 }
1408 if ctor_name == "DAutoSolve" {
1409 return try_dauto_solve_conclude(ctx, p);
1411 }
1412 if ctor_name == "DBitblastSolve" {
1413 return try_dbitblast_solve_conclude(ctx, p);
1415 }
1416 if ctor_name == "DTabulateSolve" {
1417 return try_dtabulate_solve_conclude(ctx, p);
1419 }
1420 if ctor_name == "DHwAutoSolve" {
1421 return try_dhw_auto_solve_conclude(ctx, p);
1423 }
1424 if ctor_name == "DInversion" {
1425 return try_dinversion_conclude(ctx, p);
1427 }
1428 }
1429 }
1430
1431 if let Term::App(partial1, new_goal) = deriv {
1434 if let Term::App(partial2, old_goal) = partial1.as_ref() {
1435 if let Term::App(ctor_term, eq_proof) = partial2.as_ref() {
1436 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1437 if ctor_name == "DRewrite" {
1438 return try_drewrite_conclude(ctx, eq_proof, old_goal, new_goal);
1439 }
1440 }
1441 }
1442 }
1443 }
1444
1445 if let Term::App(partial1, cases) = deriv {
1448 if let Term::App(partial2, motive) = partial1.as_ref() {
1449 if let Term::App(ctor_term, ind_type) = partial2.as_ref() {
1450 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1451 if ctor_name == "DDestruct" {
1452 return try_ddestruct_conclude(ctx, ind_type, motive, cases);
1453 }
1454 }
1455 }
1456 }
1457 }
1458
1459 if let Term::App(partial1, new_goal) = deriv {
1462 if let Term::App(partial2, old_goal) = partial1.as_ref() {
1463 if let Term::App(partial3, hyp_proof) = partial2.as_ref() {
1464 if let Term::App(ctor_term, hyp_name) = partial3.as_ref() {
1465 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1466 if ctor_name == "DApply" {
1467 return try_dapply_conclude(ctx, hyp_name, hyp_proof, old_goal, new_goal);
1468 }
1469 }
1470 }
1471 }
1472 }
1473 }
1474
1475 if let Term::App(partial, a) = deriv {
1477 if let Term::App(ctor_term, t) = partial.as_ref() {
1478 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1479 if ctor_name == "DRefl" {
1480 return Some(make_eq_syntax(t.as_ref(), a.as_ref()));
1481 }
1482 if ctor_name == "DCong" {
1483 return try_dcong_conclude(ctx, t, a);
1486 }
1487 }
1488 }
1489 }
1490
1491 if let Term::App(partial, d_ant) = deriv {
1493 if let Term::App(ctor_term, d_impl) = partial.as_ref() {
1494 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1495 if ctor_name == "DModusPonens" {
1496 let impl_conc = try_concludes_reduce(ctx, d_impl)?;
1498 let ant_conc = try_concludes_reduce(ctx, d_ant)?;
1499
1500 if let Some((a, b)) = extract_implication(&impl_conc) {
1502 if syntax_equal(&ant_conc, &a) {
1504 return Some(b);
1505 }
1506 }
1507 return Some(make_sname_error());
1509 }
1510 if ctor_name == "DUnivElim" {
1511 let conc = try_concludes_reduce(ctx, d_impl)?;
1513 if let Some(body) = extract_forall_body(&conc) {
1514 return try_syn_subst_reduce(ctx, d_ant, 0, &body);
1516 }
1517 return Some(make_sname_error());
1519 }
1520 }
1521 }
1522 }
1523
1524 if let Term::App(partial1, step) = deriv {
1527 if let Term::App(partial2, base) = partial1.as_ref() {
1528 if let Term::App(ctor_term, motive) = partial2.as_ref() {
1529 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1530 if ctor_name == "DInduction" {
1531 return try_dinduction_reduce(ctx, motive, base, step);
1532 }
1533 }
1534 }
1535 }
1536 }
1537
1538 if let Term::App(partial1, cases) = deriv {
1541 if let Term::App(partial2, motive) = partial1.as_ref() {
1542 if let Term::App(ctor_term, ind_type) = partial2.as_ref() {
1543 if let Term::Global(ctor_name) = ctor_term.as_ref() {
1544 if ctor_name == "DElim" {
1545 return try_delim_conclude(ctx, ind_type, motive, cases);
1546 }
1547 }
1548 }
1549 }
1550 }
1551
1552 None
1553}
1554
1555fn extract_implication(term: &Term) -> Option<(Term, Term)> {
1562 if let Term::App(outer, b) = term {
1564 if let Term::App(sapp_outer, x) = outer.as_ref() {
1565 if let Term::Global(ctor) = sapp_outer.as_ref() {
1566 if ctor == "SApp" {
1567 if let Term::App(inner, a) = x.as_ref() {
1569 if let Term::App(sapp_inner, sname_implies) = inner.as_ref() {
1570 if let Term::Global(ctor2) = sapp_inner.as_ref() {
1571 if ctor2 == "SApp" {
1572 if let Term::App(sname, text) = sname_implies.as_ref() {
1574 if let Term::Global(sname_ctor) = sname.as_ref() {
1575 if sname_ctor == "SName" {
1576 if let Term::Lit(Literal::Text(s)) = text.as_ref() {
1577 if s == "Implies" || s == "implies" {
1578 return Some((
1579 a.as_ref().clone(),
1580 b.as_ref().clone(),
1581 ));
1582 }
1583 }
1584 }
1585 }
1586 }
1587 }
1588 }
1589 }
1590 }
1591 }
1592 }
1593 }
1594 }
1595 None
1596}
1597
1598fn extract_implications(term: &Term) -> Option<(Vec<Term>, Term)> {
1603 let mut hyps = Vec::new();
1604 let mut current = term.clone();
1605
1606 while let Some((hyp, rest)) = extract_implication(¤t) {
1607 hyps.push(hyp);
1608 current = rest;
1609 }
1610
1611 if hyps.is_empty() {
1612 None
1613 } else {
1614 Some((hyps, current))
1615 }
1616}
1617
1618fn extract_forall_body(term: &Term) -> Option<Term> {
1625 if let Term::App(outer, lam) = term {
1627 if let Term::App(sapp_outer, x) = outer.as_ref() {
1628 if let Term::Global(ctor) = sapp_outer.as_ref() {
1629 if ctor == "SApp" {
1630 if let Term::App(sname, text) = x.as_ref() {
1632 if let Term::Global(sname_ctor) = sname.as_ref() {
1633 if sname_ctor == "SName" {
1634 if let Term::Lit(Literal::Text(s)) = text.as_ref() {
1635 if s == "Forall" {
1636 return extract_slam_body(lam);
1638 }
1639 }
1640 }
1641 }
1642 }
1643
1644 if let Term::App(inner, _t) = x.as_ref() {
1646 if let Term::App(sapp_inner, sname_forall) = inner.as_ref() {
1647 if let Term::Global(ctor2) = sapp_inner.as_ref() {
1648 if ctor2 == "SApp" {
1649 if let Term::App(sname, text) = sname_forall.as_ref() {
1650 if let Term::Global(sname_ctor) = sname.as_ref() {
1651 if sname_ctor == "SName" {
1652 if let Term::Lit(Literal::Text(s)) = text.as_ref() {
1653 if s == "Forall" {
1654 return extract_slam_body(lam);
1655 }
1656 }
1657 }
1658 }
1659 }
1660 }
1661 }
1662 }
1663 }
1664 }
1665 }
1666 }
1667 }
1668 None
1669}
1670
1671fn extract_slam_body(term: &Term) -> Option<Term> {
1673 if let Term::App(inner, body) = term {
1674 if let Term::App(slam, _t) = inner.as_ref() {
1675 if let Term::Global(name) = slam.as_ref() {
1676 if name == "SLam" {
1677 return Some(body.as_ref().clone());
1678 }
1679 }
1680 }
1681 }
1682 None
1683}
1684
1685fn syntax_equal(a: &Term, b: &Term) -> bool {
1687 a == b
1688}
1689
1690fn make_sname_error() -> Term {
1692 Term::App(
1693 Box::new(Term::Global("SName".to_string())),
1694 Box::new(Term::Lit(Literal::Text("Error".to_string()))),
1695 )
1696}
1697
1698fn make_sname(s: &str) -> Term {
1700 Term::App(
1701 Box::new(Term::Global("SName".to_string())),
1702 Box::new(Term::Lit(Literal::Text(s.to_string()))),
1703 )
1704}
1705
1706fn make_slit(n: i64) -> Term {
1708 Term::App(
1709 Box::new(Term::Global("SLit".to_string())),
1710 Box::new(Term::Lit(Literal::Int(n))),
1711 )
1712}
1713
1714fn make_sapp(f: Term, x: Term) -> Term {
1716 Term::App(
1717 Box::new(Term::App(
1718 Box::new(Term::Global("SApp".to_string())),
1719 Box::new(f),
1720 )),
1721 Box::new(x),
1722 )
1723}
1724
1725fn make_spi(a: Term, b: Term) -> Term {
1727 Term::App(
1728 Box::new(Term::App(
1729 Box::new(Term::Global("SPi".to_string())),
1730 Box::new(a),
1731 )),
1732 Box::new(b),
1733 )
1734}
1735
1736fn make_slam(a: Term, b: Term) -> Term {
1738 Term::App(
1739 Box::new(Term::App(
1740 Box::new(Term::Global("SLam".to_string())),
1741 Box::new(a),
1742 )),
1743 Box::new(b),
1744 )
1745}
1746
1747fn make_ssort(u: Term) -> Term {
1749 Term::App(
1750 Box::new(Term::Global("SSort".to_string())),
1751 Box::new(u),
1752 )
1753}
1754
1755fn make_svar(n: i64) -> Term {
1757 Term::App(
1758 Box::new(Term::Global("SVar".to_string())),
1759 Box::new(Term::Lit(Literal::Int(n))),
1760 )
1761}
1762
1763fn term_to_syntax(term: &Term) -> Option<Term> {
1776 match term {
1777 Term::Global(name) => Some(make_sname(name)),
1778
1779 Term::Var(name) => {
1780 Some(make_sname(name))
1782 }
1783
1784 Term::App(f, x) => {
1785 let sf = term_to_syntax(f)?;
1786 let sx = term_to_syntax(x)?;
1787 Some(make_sapp(sf, sx))
1788 }
1789
1790 Term::Pi { param_type, body_type, .. } => {
1791 let sp = term_to_syntax(param_type)?;
1792 let sb = term_to_syntax(body_type)?;
1793 Some(make_spi(sp, sb))
1794 }
1795
1796 Term::Lambda { param_type, body, .. } => {
1797 let sp = term_to_syntax(param_type)?;
1798 let sb = term_to_syntax(body)?;
1799 Some(make_slam(sp, sb))
1800 }
1801
1802 Term::Sort(Universe::Type(n)) => {
1803 let u = Term::App(
1804 Box::new(Term::Global("UType".to_string())),
1805 Box::new(Term::Lit(Literal::Int(*n as i64))),
1806 );
1807 Some(make_ssort(u))
1808 }
1809
1810 Term::Sort(Universe::Prop) => {
1811 let u = Term::Global("UProp".to_string());
1812 Some(make_ssort(u))
1813 }
1814
1815 Term::Lit(Literal::Int(n)) => Some(make_slit(*n)),
1816
1817 Term::Lit(Literal::Text(s)) => Some(make_sname(s)),
1818
1819 Term::Lit(Literal::Float(_))
1821 | Term::Lit(Literal::Duration(_))
1822 | Term::Lit(Literal::Date(_))
1823 | Term::Lit(Literal::Moment(_)) => None,
1824
1825 Term::Match { .. } | Term::Fix { .. } | Term::Hole => None,
1827 }
1828}
1829
1830fn make_hint_derivation(hint_name: &str, goal: &Term) -> Term {
1834 let hint_marker = make_sapp(make_sname("Hint"), make_sname(hint_name));
1837
1838 Term::App(
1841 Box::new(Term::Global("DAutoSolve".to_string())),
1842 Box::new(goal.clone()),
1843 )
1844}
1845
1846fn try_apply_hint(ctx: &Context, hint_name: &str, hint_type: &Term, goal: &Term) -> Option<Term> {
1851 let hint_syntax = term_to_syntax(hint_type)?;
1853
1854 let norm_hint = normalize(ctx, &hint_syntax);
1856 let norm_goal = normalize(ctx, goal);
1857
1858 if syntax_equal(&norm_hint, &norm_goal) {
1860 return Some(make_hint_derivation(hint_name, goal));
1861 }
1862
1863 if let Term::App(outer, q) = &hint_syntax {
1866 if let Term::App(pi_ctor, p) = outer.as_ref() {
1867 if let Term::Global(name) = pi_ctor.as_ref() {
1868 if name == "SPi" {
1869 let norm_q = normalize(ctx, q);
1871 if syntax_equal(&norm_q, &norm_goal) {
1872 }
1876 }
1877 }
1878 }
1879 }
1880
1881 None
1882}
1883
1884fn make_forall_syntax(body: &Term) -> Term {
1886 let type0 = Term::App(
1887 Box::new(Term::Global("SSort".to_string())),
1888 Box::new(Term::App(
1889 Box::new(Term::Global("UType".to_string())),
1890 Box::new(Term::Lit(Literal::Int(0))),
1891 )),
1892 );
1893
1894 let slam = Term::App(
1896 Box::new(Term::App(
1897 Box::new(Term::Global("SLam".to_string())),
1898 Box::new(type0.clone()),
1899 )),
1900 Box::new(body.clone()),
1901 );
1902
1903 Term::App(
1905 Box::new(Term::App(
1906 Box::new(Term::Global("SApp".to_string())),
1907 Box::new(Term::App(
1908 Box::new(Term::App(
1909 Box::new(Term::Global("SApp".to_string())),
1910 Box::new(Term::App(
1911 Box::new(Term::Global("SName".to_string())),
1912 Box::new(Term::Lit(Literal::Text("Forall".to_string()))),
1913 )),
1914 )),
1915 Box::new(type0),
1916 )),
1917 )),
1918 Box::new(slam),
1919 )
1920}
1921
1922fn make_eq_syntax(type_s: &Term, term: &Term) -> Term {
1930 let eq_name = Term::App(
1931 Box::new(Term::Global("SName".to_string())),
1932 Box::new(Term::Lit(Literal::Text("Eq".to_string()))),
1933 );
1934
1935 let app1 = Term::App(
1937 Box::new(Term::App(
1938 Box::new(Term::Global("SApp".to_string())),
1939 Box::new(eq_name),
1940 )),
1941 Box::new(type_s.clone()),
1942 );
1943
1944 let app2 = Term::App(
1946 Box::new(Term::App(
1947 Box::new(Term::Global("SApp".to_string())),
1948 Box::new(app1),
1949 )),
1950 Box::new(term.clone()),
1951 );
1952
1953 Term::App(
1955 Box::new(Term::App(
1956 Box::new(Term::Global("SApp".to_string())),
1957 Box::new(app2),
1958 )),
1959 Box::new(term.clone()),
1960 )
1961}
1962
1963fn extract_eq(term: &Term) -> Option<(Term, Term, Term)> {
1967 if let Term::App(outer, b) = term {
1969 if let Term::App(sapp_outer, x) = outer.as_ref() {
1970 if let Term::Global(ctor) = sapp_outer.as_ref() {
1971 if ctor == "SApp" {
1972 if let Term::App(inner, a) = x.as_ref() {
1974 if let Term::App(sapp_inner, y) = inner.as_ref() {
1975 if let Term::Global(ctor2) = sapp_inner.as_ref() {
1976 if ctor2 == "SApp" {
1977 if let Term::App(inner2, t) = y.as_ref() {
1979 if let Term::App(sapp_inner2, sname_eq) = inner2.as_ref() {
1980 if let Term::Global(ctor3) = sapp_inner2.as_ref() {
1981 if ctor3 == "SApp" {
1982 if let Term::App(sname, text) = sname_eq.as_ref()
1984 {
1985 if let Term::Global(sname_ctor) =
1986 sname.as_ref()
1987 {
1988 if sname_ctor == "SName" {
1989 if let Term::Lit(Literal::Text(s)) =
1990 text.as_ref()
1991 {
1992 if s == "Eq" {
1993 return Some((
1994 t.as_ref().clone(),
1995 a.as_ref().clone(),
1996 b.as_ref().clone(),
1997 ));
1998 }
1999 }
2000 }
2001 }
2002 }
2003 }
2004 }
2005 }
2006 }
2007 }
2008 }
2009 }
2010 }
2011 }
2012 }
2013 }
2014 }
2015 None
2016}
2017
2018fn make_drefl(type_s: &Term, term: &Term) -> Term {
2020 let drefl = Term::Global("DRefl".to_string());
2021 let app1 = Term::App(Box::new(drefl), Box::new(type_s.clone()));
2022 Term::App(Box::new(app1), Box::new(term.clone()))
2023}
2024
2025fn make_error_derivation() -> Term {
2027 let daxiom = Term::Global("DAxiom".to_string());
2028 let error = make_sname_error();
2029 Term::App(Box::new(daxiom), Box::new(error))
2030}
2031
2032fn make_daxiom(goal: &Term) -> Term {
2034 let daxiom = Term::Global("DAxiom".to_string());
2035 Term::App(Box::new(daxiom), Box::new(goal.clone()))
2036}
2037
2038fn try_try_refl_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2044 let norm_goal = normalize(ctx, goal);
2046
2047 if let Some((type_s, left, right)) = extract_eq(&norm_goal) {
2049 if syntax_equal(&left, &right) {
2051 return Some(make_drefl(&type_s, &left));
2053 }
2054 }
2055
2056 Some(make_error_derivation())
2058}
2059
2060use crate::ring;
2065use crate::lia;
2066use crate::cc;
2067use crate::simp;
2068
2069fn try_try_ring_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2077 let norm_goal = normalize(ctx, goal);
2079
2080 if let Some((type_s, left, right)) = extract_eq(&norm_goal) {
2082 if !is_ring_type(&type_s) {
2084 return Some(make_error_derivation());
2085 }
2086
2087 let poly_left = match ring::reify(&left) {
2089 Ok(p) => p,
2090 Err(_) => return Some(make_error_derivation()),
2091 };
2092 let poly_right = match ring::reify(&right) {
2093 Ok(p) => p,
2094 Err(_) => return Some(make_error_derivation()),
2095 };
2096
2097 if poly_left.canonical_eq(&poly_right) {
2099 return Some(Term::App(
2101 Box::new(Term::Global("DRingSolve".to_string())),
2102 Box::new(norm_goal),
2103 ));
2104 }
2105 }
2106
2107 Some(make_error_derivation())
2109}
2110
2111fn try_dring_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2115 let norm_goal = normalize(ctx, goal);
2116
2117 if let Some((type_s, left, right)) = extract_eq(&norm_goal) {
2119 if !is_ring_type(&type_s) {
2121 return Some(make_sname_error());
2122 }
2123
2124 let poly_left = match ring::reify(&left) {
2126 Ok(p) => p,
2127 Err(_) => return Some(make_sname_error()),
2128 };
2129 let poly_right = match ring::reify(&right) {
2130 Ok(p) => p,
2131 Err(_) => return Some(make_sname_error()),
2132 };
2133
2134 if poly_left.canonical_eq(&poly_right) {
2135 return Some(norm_goal);
2136 }
2137 }
2138
2139 Some(make_sname_error())
2140}
2141
2142fn is_ring_type(type_term: &Term) -> bool {
2144 if let Some(name) = extract_sname_from_syntax(type_term) {
2145 return name == "Int" || name == "Nat";
2146 }
2147 false
2148}
2149
2150fn extract_sname_from_syntax(term: &Term) -> Option<String> {
2152 if let Term::App(ctor, arg) = term {
2153 if let Term::Global(name) = ctor.as_ref() {
2154 if name == "SName" {
2155 if let Term::Lit(Literal::Text(s)) = arg.as_ref() {
2156 return Some(s.clone());
2157 }
2158 }
2159 }
2160 }
2161 None
2162}
2163
2164fn try_try_lia_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2176 let norm_goal = normalize(ctx, goal);
2178
2179 if let Some((rel, lhs_term, rhs_term)) = lia::extract_comparison(&norm_goal) {
2181 let lhs = match lia::reify_linear(&lhs_term) {
2183 Ok(l) => l,
2184 Err(_) => return Some(make_error_derivation()),
2185 };
2186 let rhs = match lia::reify_linear(&rhs_term) {
2187 Ok(r) => r,
2188 Err(_) => return Some(make_error_derivation()),
2189 };
2190
2191 if let Some(negated) = lia::goal_to_negated_constraint(&rel, &lhs, &rhs) {
2193 if lia::fourier_motzkin_unsat(&[negated]) {
2195 return Some(Term::App(
2197 Box::new(Term::Global("DLiaSolve".to_string())),
2198 Box::new(norm_goal),
2199 ));
2200 }
2201 }
2202 }
2203
2204 Some(make_error_derivation())
2206}
2207
2208fn try_dlia_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2212 let norm_goal = normalize(ctx, goal);
2213
2214 if let Some((rel, lhs_term, rhs_term)) = lia::extract_comparison(&norm_goal) {
2216 let lhs = match lia::reify_linear(&lhs_term) {
2218 Ok(l) => l,
2219 Err(_) => return Some(make_sname_error()),
2220 };
2221 let rhs = match lia::reify_linear(&rhs_term) {
2222 Ok(r) => r,
2223 Err(_) => return Some(make_sname_error()),
2224 };
2225
2226 if let Some(negated) = lia::goal_to_negated_constraint(&rel, &lhs, &rhs) {
2228 if lia::fourier_motzkin_unsat(&[negated]) {
2229 return Some(norm_goal);
2230 }
2231 }
2232 }
2233
2234 Some(make_sname_error())
2235}
2236
2237fn try_try_cc_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2249 let norm_goal = normalize(ctx, goal);
2251
2252 if cc::check_goal(&norm_goal) {
2256 return Some(Term::App(
2258 Box::new(Term::Global("DccSolve".to_string())),
2259 Box::new(norm_goal),
2260 ));
2261 }
2262
2263 Some(make_error_derivation())
2265}
2266
2267fn try_dcc_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2271 let norm_goal = normalize(ctx, goal);
2272
2273 if cc::check_goal(&norm_goal) {
2275 return Some(norm_goal);
2276 }
2277
2278 Some(make_sname_error())
2279}
2280
2281fn try_try_simp_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2291 let norm_goal = normalize(ctx, goal);
2293
2294 if simp::check_goal(&norm_goal) {
2299 return Some(Term::App(
2301 Box::new(Term::Global("DSimpSolve".to_string())),
2302 Box::new(norm_goal),
2303 ));
2304 }
2305
2306 Some(make_error_derivation())
2308}
2309
2310fn try_dsimp_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2314 let norm_goal = normalize(ctx, goal);
2315
2316 if simp::check_goal(&norm_goal) {
2318 return Some(norm_goal);
2319 }
2320
2321 Some(make_sname_error())
2322}
2323
2324fn try_try_omega_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2341 let norm_goal = normalize(ctx, goal);
2342
2343 if let Some((hyps, conclusion)) = extract_implications(&norm_goal) {
2345 let mut constraints = Vec::new();
2347
2348 for hyp in &hyps {
2349 if let Some((rel, lhs_term, rhs_term)) = omega::extract_comparison(hyp) {
2351 if let (Some(lhs), Some(rhs)) =
2352 (omega::reify_int_linear(&lhs_term), omega::reify_int_linear(&rhs_term))
2353 {
2354 match rel.as_str() {
2358 "Lt" | "lt" => {
2359 let mut expr = lhs.sub(&rhs);
2361 expr.constant += 1;
2362 constraints.push(omega::IntConstraint { expr, strict: false });
2363 }
2364 "Le" | "le" => {
2365 constraints.push(omega::IntConstraint {
2367 expr: lhs.sub(&rhs),
2368 strict: false,
2369 });
2370 }
2371 "Gt" | "gt" => {
2372 let mut expr = rhs.sub(&lhs);
2374 expr.constant += 1;
2375 constraints.push(omega::IntConstraint { expr, strict: false });
2376 }
2377 "Ge" | "ge" => {
2378 constraints.push(omega::IntConstraint {
2380 expr: rhs.sub(&lhs),
2381 strict: false,
2382 });
2383 }
2384 _ => {}
2385 }
2386 }
2387 }
2388 }
2389
2390 if let Some((rel, lhs_term, rhs_term)) = omega::extract_comparison(&conclusion) {
2392 if let (Some(lhs), Some(rhs)) =
2393 (omega::reify_int_linear(&lhs_term), omega::reify_int_linear(&rhs_term))
2394 {
2395 if let Some(neg_constraint) = omega::goal_to_negated_constraint(&rel, &lhs, &rhs) {
2397 let mut all_constraints = constraints;
2398 all_constraints.push(neg_constraint);
2399
2400 if omega::omega_unsat(&all_constraints) {
2401 return Some(Term::App(
2402 Box::new(Term::Global("DOmegaSolve".to_string())),
2403 Box::new(norm_goal),
2404 ));
2405 }
2406 }
2407 }
2408 }
2409
2410 return Some(make_error_derivation());
2412 }
2413
2414 if let Some((rel, lhs_term, rhs_term)) = omega::extract_comparison(&norm_goal) {
2416 if let (Some(lhs), Some(rhs)) =
2417 (omega::reify_int_linear(&lhs_term), omega::reify_int_linear(&rhs_term))
2418 {
2419 if let Some(constraint) = omega::goal_to_negated_constraint(&rel, &lhs, &rhs) {
2420 if omega::omega_unsat(&[constraint]) {
2421 return Some(Term::App(
2422 Box::new(Term::Global("DOmegaSolve".to_string())),
2423 Box::new(norm_goal),
2424 ));
2425 }
2426 }
2427 }
2428 }
2429
2430 Some(make_error_derivation())
2431}
2432
2433fn try_domega_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2437 let norm_goal = normalize(ctx, goal);
2438
2439 if let Some((hyps, conclusion)) = extract_implications(&norm_goal) {
2442 let mut constraints = Vec::new();
2443
2444 for hyp in &hyps {
2445 if let Some((rel, lhs_term, rhs_term)) = omega::extract_comparison(hyp) {
2446 if let (Some(lhs), Some(rhs)) =
2447 (omega::reify_int_linear(&lhs_term), omega::reify_int_linear(&rhs_term))
2448 {
2449 match rel.as_str() {
2450 "Lt" | "lt" => {
2451 let mut expr = lhs.sub(&rhs);
2452 expr.constant += 1;
2453 constraints.push(omega::IntConstraint { expr, strict: false });
2454 }
2455 "Le" | "le" => {
2456 constraints.push(omega::IntConstraint {
2457 expr: lhs.sub(&rhs),
2458 strict: false,
2459 });
2460 }
2461 "Gt" | "gt" => {
2462 let mut expr = rhs.sub(&lhs);
2463 expr.constant += 1;
2464 constraints.push(omega::IntConstraint { expr, strict: false });
2465 }
2466 "Ge" | "ge" => {
2467 constraints.push(omega::IntConstraint {
2468 expr: rhs.sub(&lhs),
2469 strict: false,
2470 });
2471 }
2472 _ => {}
2473 }
2474 }
2475 }
2476 }
2477
2478 if let Some((rel, lhs_term, rhs_term)) = omega::extract_comparison(&conclusion) {
2479 if let (Some(lhs), Some(rhs)) =
2480 (omega::reify_int_linear(&lhs_term), omega::reify_int_linear(&rhs_term))
2481 {
2482 if let Some(neg_constraint) = omega::goal_to_negated_constraint(&rel, &lhs, &rhs) {
2483 let mut all_constraints = constraints;
2484 all_constraints.push(neg_constraint);
2485
2486 if omega::omega_unsat(&all_constraints) {
2487 return Some(norm_goal);
2488 }
2489 }
2490 }
2491 }
2492
2493 return Some(make_sname_error());
2494 }
2495
2496 if let Some((rel, lhs_term, rhs_term)) = omega::extract_comparison(&norm_goal) {
2498 if let (Some(lhs), Some(rhs)) =
2499 (omega::reify_int_linear(&lhs_term), omega::reify_int_linear(&rhs_term))
2500 {
2501 if let Some(constraint) = omega::goal_to_negated_constraint(&rel, &lhs, &rhs) {
2502 if omega::omega_unsat(&[constraint]) {
2503 return Some(norm_goal);
2504 }
2505 }
2506 }
2507 }
2508
2509 Some(make_sname_error())
2510}
2511
2512fn is_error_derivation(term: &Term) -> bool {
2520 if let Term::App(ctor, arg) = term {
2522 if let Term::Global(name) = ctor.as_ref() {
2523 if name == "DAxiom" {
2524 if let Term::App(sname, inner) = arg.as_ref() {
2526 if let Term::Global(sn) = sname.as_ref() {
2527 if sn == "SName" {
2528 if let Term::Lit(Literal::Text(s)) = inner.as_ref() {
2529 return s == "Error";
2530 }
2531 }
2532 if sn == "SApp" {
2533 return true; }
2536 }
2537 }
2538 if let Term::Global(sn) = arg.as_ref() {
2540 return sn == "Error";
2542 }
2543 return true; }
2545 }
2546 }
2547 false
2548}
2549
2550fn try_try_bitblast_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2563 let norm_goal = normalize(ctx, goal);
2564
2565 if let Some((type_s, left, right)) = extract_eq_syntax_parts(&norm_goal) {
2567 if !is_bit_type(&type_s) {
2569 return Some(make_error_derivation());
2570 }
2571
2572 let fuel = 1000;
2577 let left_eval = try_syn_eval_reduce(ctx, fuel, &left)?;
2578 let right_eval = try_syn_eval_reduce(ctx, fuel, &right)?;
2579
2580 if syntax_equal(&left_eval, &right_eval) {
2581 return Some(Term::App(
2582 Box::new(Term::Global("DBitblastSolve".to_string())),
2583 Box::new(norm_goal),
2584 ));
2585 }
2586 }
2587
2588 Some(make_error_derivation())
2589}
2590
2591fn syntax_to_term(syntax: &Term) -> Option<Term> {
2600 if let Term::App(ctor, inner) = syntax {
2601 if let Term::Global(name) = ctor.as_ref() {
2602 match name.as_str() {
2603 "SName" => {
2604 if let Term::Lit(Literal::Text(s)) = inner.as_ref() {
2605 return Some(Term::Global(s.clone()));
2606 }
2607 }
2608 "SLit" => {
2609 if let Term::Lit(Literal::Int(n)) = inner.as_ref() {
2610 return Some(Term::Lit(Literal::Int(*n)));
2611 }
2612 }
2613 "SVar" => {
2614 if let Term::Lit(Literal::Int(n)) = inner.as_ref() {
2615 return Some(Term::Var(format!("v{}", n)));
2616 }
2617 }
2618 "SGlobal" => {
2619 if let Term::Lit(Literal::Int(n)) = inner.as_ref() {
2620 return Some(Term::Var(format!("g{}", n)));
2621 }
2622 }
2623 _ => {}
2624 }
2625 }
2626 }
2627
2628 if let Term::App(outer, second) = syntax {
2630 if let Term::App(sctor, first) = outer.as_ref() {
2631 if let Term::Global(name) = sctor.as_ref() {
2632 match name.as_str() {
2633 "SApp" => {
2634 let f = syntax_to_term(first)?;
2635 let x = syntax_to_term(second)?;
2636 return Some(Term::App(Box::new(f), Box::new(x)));
2637 }
2638 "SLam" => {
2639 let param_type = syntax_to_term(first)?;
2640 let body = syntax_to_term(second)?;
2641 return Some(Term::Lambda {
2642 param: "_".to_string(),
2643 param_type: Box::new(param_type),
2644 body: Box::new(body),
2645 });
2646 }
2647 "SPi" => {
2648 let param_type = syntax_to_term(first)?;
2649 let body_type = syntax_to_term(second)?;
2650 return Some(Term::Pi {
2651 param: "_".to_string(),
2652 param_type: Box::new(param_type),
2653 body_type: Box::new(body_type),
2654 });
2655 }
2656 _ => {}
2657 }
2658 }
2659 }
2660 }
2661
2662 if let Term::App(outer, third) = syntax {
2665 if let Term::App(mid, second) = outer.as_ref() {
2666 if let Term::App(inner, first) = mid.as_ref() {
2667 if let Term::Global(name) = inner.as_ref() {
2668 if name == "SMatch" {
2669 let disc = syntax_to_term(first)?;
2670 let motive = syntax_to_term(second)?;
2671 let _ = third;
2673 return Some(Term::Match {
2674 discriminant: Box::new(disc),
2675 motive: Box::new(motive),
2676 cases: vec![],
2677 });
2678 }
2679 }
2680 }
2681 }
2682 }
2683
2684 None
2685}
2686
2687fn is_bit_type(term: &Term) -> bool {
2689 if let Term::App(ctor, inner) = term {
2691 if let Term::Global(name) = ctor.as_ref() {
2692 if name == "SName" {
2693 if let Term::Lit(Literal::Text(s)) = inner.as_ref() {
2694 return s == "Bit";
2695 }
2696 }
2697 }
2698 }
2699 false
2700}
2701
2702fn syntax_subst_var(term: &Term, idx: i64, replacement: &Term) -> Term {
2705 if let Term::App(ctor, inner) = term {
2707 if let Term::Global(name) = ctor.as_ref() {
2708 if name == "SVar" {
2709 if let Term::Lit(Literal::Int(n)) = inner.as_ref() {
2710 if *n == idx {
2711 return replacement.clone();
2712 } else if *n > idx {
2713 return make_svar(*n - 1);
2715 } else {
2716 return term.clone();
2717 }
2718 }
2719 }
2720 }
2721 }
2722
2723 if let Term::App(outer, second) = term {
2725 if let Term::App(sctor, first) = outer.as_ref() {
2726 if let Term::Global(name) = sctor.as_ref() {
2727 match name.as_str() {
2728 "SApp" => {
2729 let f = syntax_subst_var(first, idx, replacement);
2730 let x = syntax_subst_var(second, idx, replacement);
2731 return make_sapp(f, x);
2732 }
2733 "SPi" => {
2734 let param_t = syntax_subst_var(first, idx, replacement);
2736 let body = syntax_subst_var(second, idx + 1, replacement);
2737 return make_spi(param_t, body);
2738 }
2739 "SLam" => {
2740 let param_t = syntax_subst_var(first, idx, replacement);
2741 let body = syntax_subst_var(second, idx + 1, replacement);
2742 return make_slam(param_t, body);
2743 }
2744 _ => {}
2745 }
2746 }
2747 }
2748 }
2749
2750 term.clone()
2752}
2753
2754fn try_try_tabulate_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2765 let norm_goal = normalize(ctx, goal);
2766
2767 if let Some((param_type, body)) = extract_spi(&norm_goal) {
2769 if !is_bit_type(¶m_type) {
2771 return Some(make_error_derivation());
2772 }
2773
2774 let body_b0 = syntax_subst_var(&body, 0, &make_sname("B0"));
2776 let body_b1 = syntax_subst_var(&body, 0, &make_sname("B1"));
2777
2778 let ok_b0 = tabulate_verify_case(ctx, &body_b0);
2780 let ok_b1 = tabulate_verify_case(ctx, &body_b1);
2781
2782 if ok_b0 && ok_b1 {
2783 return Some(Term::App(
2784 Box::new(Term::Global("DTabulateSolve".to_string())),
2785 Box::new(norm_goal),
2786 ));
2787 }
2788
2789 return Some(make_error_derivation());
2790 }
2791
2792 Some(make_error_derivation())
2794}
2795
2796fn tabulate_verify_case(ctx: &Context, case: &Term) -> bool {
2801 let norm = normalize(ctx, case);
2802
2803 if let Some((param_type, _)) = extract_spi(&norm) {
2805 if is_bit_type(¶m_type) {
2806 if let Some(result) = try_try_tabulate_reduce(ctx, &norm) {
2807 return !is_error_derivation(&result);
2808 }
2809 }
2810 return false;
2811 }
2812
2813 if let Some((type_s, left, right)) = extract_eq_syntax_parts(&norm) {
2815 let fuel = 1000;
2816 if let (Some(left_eval), Some(right_eval)) = (
2817 try_syn_eval_reduce(ctx, fuel, &left),
2818 try_syn_eval_reduce(ctx, fuel, &right),
2819 ) {
2820 return syntax_equal(&left_eval, &right_eval);
2821 }
2822 if let Some(full_eval) = try_syn_eval_reduce(ctx, fuel, &norm) {
2824 if is_sname_with_value(&full_eval, "True") {
2825 return true;
2826 }
2827 }
2828 return false;
2829 }
2830
2831 let fuel = 1000;
2833 if let Some(eval) = try_syn_eval_reduce(ctx, fuel, &norm) {
2834 if is_sname_with_value(&eval, "True") {
2835 return true;
2836 }
2837 }
2838
2839 false
2840}
2841
2842fn is_sname_with_value(term: &Term, value: &str) -> bool {
2844 if let Term::App(ctor, inner) = term {
2845 if let Term::Global(name) = ctor.as_ref() {
2846 if name == "SName" {
2847 if let Term::Lit(Literal::Text(s)) = inner.as_ref() {
2848 return s == value;
2849 }
2850 }
2851 }
2852 }
2853 false
2854}
2855
2856fn try_dbitblast_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2858 let norm_goal = normalize(ctx, goal);
2859 if let Some((type_s, left, right)) = extract_eq_syntax_parts(&norm_goal) {
2860 if is_bit_type(&type_s) {
2861 let fuel = 1000;
2862 let left_eval = try_syn_eval_reduce(ctx, fuel, &left)?;
2863 let right_eval = try_syn_eval_reduce(ctx, fuel, &right)?;
2864 if syntax_equal(&left_eval, &right_eval) {
2865 return Some(norm_goal);
2866 }
2867 }
2868 }
2869 None
2870}
2871
2872fn try_dtabulate_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2874 let norm_goal = normalize(ctx, goal);
2875 if let Some((param_type, _)) = extract_spi(&norm_goal) {
2877 if is_bit_type(¶m_type) {
2878 if let Some(result) = try_try_tabulate_reduce(ctx, &norm_goal) {
2879 if !is_error_derivation(&result) {
2880 return Some(norm_goal);
2881 }
2882 }
2883 }
2884 }
2885 None
2886}
2887
2888fn try_dhw_auto_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2890 if let Some(result) = try_dbitblast_solve_conclude(ctx, goal) {
2892 return Some(result);
2893 }
2894 try_dauto_solve_conclude(ctx, goal)
2896}
2897
2898fn try_try_hw_auto_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2900 let norm_goal = normalize(ctx, goal);
2901
2902 if let Some(result) = try_try_bitblast_reduce(ctx, &norm_goal) {
2904 if !is_error_derivation(&result) {
2905 return Some(result);
2906 }
2907 }
2908
2909 if let Some(result) = try_try_tabulate_reduce(ctx, &norm_goal) {
2911 if !is_error_derivation(&result) {
2912 return Some(result);
2913 }
2914 }
2915
2916 try_try_auto_reduce(ctx, &norm_goal)
2918}
2919
2920fn try_try_auto_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
2921 let norm_goal = normalize(ctx, goal);
2922
2923 if let Term::App(ctor, inner) = &norm_goal {
2926 if let Term::Global(name) = ctor.as_ref() {
2927 if name == "SName" {
2928 if let Term::Lit(Literal::Text(s)) = inner.as_ref() {
2929 if s == "True" {
2930 return Some(Term::App(
2932 Box::new(Term::Global("DAutoSolve".to_string())),
2933 Box::new(norm_goal),
2934 ));
2935 }
2936 if s == "False" {
2937 return Some(make_error_derivation());
2939 }
2940 }
2941 }
2942 }
2943 }
2944
2945 if let Some(result) = try_try_simp_reduce(ctx, &norm_goal) {
2947 if !is_error_derivation(&result) {
2948 return Some(result);
2949 }
2950 }
2951
2952 if let Some(result) = try_try_ring_reduce(ctx, &norm_goal) {
2954 if !is_error_derivation(&result) {
2955 return Some(result);
2956 }
2957 }
2958
2959 if let Some(result) = try_try_cc_reduce(ctx, &norm_goal) {
2961 if !is_error_derivation(&result) {
2962 return Some(result);
2963 }
2964 }
2965
2966 if let Some(result) = try_try_omega_reduce(ctx, &norm_goal) {
2968 if !is_error_derivation(&result) {
2969 return Some(result);
2970 }
2971 }
2972
2973 if let Some(result) = try_try_lia_reduce(ctx, &norm_goal) {
2975 if !is_error_derivation(&result) {
2976 return Some(result);
2977 }
2978 }
2979
2980 for hint_name in ctx.get_hints() {
2982 if let Some(hint_type) = ctx.get_global(hint_name) {
2983 if let Some(result) = try_apply_hint(ctx, hint_name, hint_type, &norm_goal) {
2984 return Some(result);
2985 }
2986 }
2987 }
2988
2989 Some(make_error_derivation())
2991}
2992
2993fn try_dauto_solve_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
2995 let norm_goal = normalize(ctx, goal);
2996
2997 if let Term::App(ctor, inner) = &norm_goal {
2999 if let Term::Global(name) = ctor.as_ref() {
3000 if name == "SName" {
3001 if let Term::Lit(Literal::Text(s)) = inner.as_ref() {
3002 if s == "True" {
3003 return Some(norm_goal.clone());
3004 }
3005 }
3006 }
3007 }
3008 }
3009
3010 if let Some(result) = try_try_simp_reduce(ctx, &norm_goal) {
3012 if !is_error_derivation(&result) {
3013 return Some(norm_goal.clone());
3014 }
3015 }
3016 if let Some(result) = try_try_ring_reduce(ctx, &norm_goal) {
3017 if !is_error_derivation(&result) {
3018 return Some(norm_goal.clone());
3019 }
3020 }
3021 if let Some(result) = try_try_cc_reduce(ctx, &norm_goal) {
3022 if !is_error_derivation(&result) {
3023 return Some(norm_goal.clone());
3024 }
3025 }
3026 if let Some(result) = try_try_omega_reduce(ctx, &norm_goal) {
3027 if !is_error_derivation(&result) {
3028 return Some(norm_goal.clone());
3029 }
3030 }
3031 if let Some(result) = try_try_lia_reduce(ctx, &norm_goal) {
3032 if !is_error_derivation(&result) {
3033 return Some(norm_goal.clone());
3034 }
3035 }
3036
3037 for hint_name in ctx.get_hints() {
3039 if let Some(hint_type) = ctx.get_global(hint_name) {
3040 if try_apply_hint(ctx, hint_name, hint_type, &norm_goal).is_some() {
3041 return Some(norm_goal);
3042 }
3043 }
3044 }
3045
3046 Some(make_sname_error())
3047}
3048
3049fn try_induction_num_cases_reduce(ctx: &Context, ind_type: &Term) -> Option<Term> {
3059 let ind_name = match extract_inductive_name_from_syntax(ind_type) {
3061 Some(name) => name,
3062 None => {
3063 return Some(Term::Global("Zero".to_string()));
3065 }
3066 };
3067
3068 let constructors = ctx.get_constructors(&ind_name);
3070 let num_ctors = constructors.len();
3071
3072 let mut result = Term::Global("Zero".to_string());
3074 for _ in 0..num_ctors {
3075 result = Term::App(
3076 Box::new(Term::Global("Succ".to_string())),
3077 Box::new(result),
3078 );
3079 }
3080
3081 Some(result)
3082}
3083
3084fn try_induction_base_goal_reduce(
3088 ctx: &Context,
3089 ind_type: &Term,
3090 motive: &Term,
3091) -> Option<Term> {
3092 let ind_name = match extract_inductive_name_from_syntax(ind_type) {
3094 Some(name) => name,
3095 None => return Some(make_sname_error()),
3096 };
3097
3098 let constructors = ctx.get_constructors(&ind_name);
3100 if constructors.is_empty() {
3101 return Some(make_sname_error());
3102 }
3103
3104 let motive_body = match extract_slam_body(motive) {
3106 Some(body) => body,
3107 None => return Some(make_sname_error()),
3108 };
3109
3110 let (ctor_name, _) = constructors[0];
3112 build_case_expected(ctx, ctor_name, &constructors, &motive_body, ind_type)
3113}
3114
3115fn try_induction_step_goal_reduce(
3119 ctx: &Context,
3120 ind_type: &Term,
3121 motive: &Term,
3122 ctor_idx: &Term,
3123) -> Option<Term> {
3124 let ind_name = match extract_inductive_name_from_syntax(ind_type) {
3126 Some(name) => name,
3127 None => return Some(make_sname_error()),
3128 };
3129
3130 let constructors = ctx.get_constructors(&ind_name);
3132 if constructors.is_empty() {
3133 return Some(make_sname_error());
3134 }
3135
3136 let idx = nat_to_usize(ctor_idx)?;
3138 if idx >= constructors.len() {
3139 return Some(make_sname_error());
3140 }
3141
3142 let motive_body = match extract_slam_body(motive) {
3144 Some(body) => body,
3145 None => return Some(make_sname_error()),
3146 };
3147
3148 let (ctor_name, _) = constructors[idx];
3150 build_case_expected(ctx, ctor_name, &constructors, &motive_body, ind_type)
3151}
3152
3153fn nat_to_usize(term: &Term) -> Option<usize> {
3159 match term {
3160 Term::Global(name) if name == "Zero" => Some(0),
3161 Term::App(succ, inner) => {
3162 if let Term::Global(name) = succ.as_ref() {
3163 if name == "Succ" {
3164 return nat_to_usize(inner).map(|n| n + 1);
3165 }
3166 }
3167 None
3168 }
3169 _ => None,
3170 }
3171}
3172
3173fn try_try_induction_reduce(
3179 ctx: &Context,
3180 ind_type: &Term,
3181 motive: &Term,
3182 cases: &Term,
3183) -> Option<Term> {
3184 let ind_name = match extract_inductive_name_from_syntax(ind_type) {
3186 Some(name) => name,
3187 None => return Some(make_error_derivation()),
3188 };
3189
3190 let constructors = ctx.get_constructors(&ind_name);
3192 if constructors.is_empty() {
3193 return Some(make_error_derivation());
3194 }
3195
3196 let case_proofs = match extract_case_proofs(cases) {
3198 Some(proofs) => proofs,
3199 None => return Some(make_error_derivation()),
3200 };
3201
3202 if case_proofs.len() != constructors.len() {
3204 return Some(make_error_derivation());
3205 }
3206
3207 Some(Term::App(
3209 Box::new(Term::App(
3210 Box::new(Term::App(
3211 Box::new(Term::Global("DElim".to_string())),
3212 Box::new(ind_type.clone()),
3213 )),
3214 Box::new(motive.clone()),
3215 )),
3216 Box::new(cases.clone()),
3217 ))
3218}
3219
3220fn try_dinduction_reduce(
3235 ctx: &Context,
3236 motive: &Term,
3237 base: &Term,
3238 step: &Term,
3239) -> Option<Term> {
3240 let norm_motive = normalize(ctx, motive);
3242 let norm_base = normalize(ctx, base);
3243 let norm_step = normalize(ctx, step);
3244
3245 let motive_body = match extract_slam_body(&norm_motive) {
3247 Some(body) => body,
3248 None => return Some(make_sname_error()),
3249 };
3250
3251 let zero = make_sname("Zero");
3253 let expected_base = match try_syn_subst_reduce(ctx, &zero, 0, &motive_body) {
3254 Some(b) => b,
3255 None => return Some(make_sname_error()),
3256 };
3257
3258 let base_conc = match try_concludes_reduce(ctx, &norm_base) {
3260 Some(c) => c,
3261 None => return Some(make_sname_error()),
3262 };
3263
3264 if !syntax_equal(&base_conc, &expected_base) {
3266 return Some(make_sname_error());
3267 }
3268
3269 let expected_step = match build_induction_step_formula(ctx, &motive_body) {
3271 Some(s) => s,
3272 None => return Some(make_sname_error()),
3273 };
3274
3275 let step_conc = match try_concludes_reduce(ctx, &norm_step) {
3277 Some(c) => c,
3278 None => return Some(make_sname_error()),
3279 };
3280
3281 if !syntax_equal(&step_conc, &expected_step) {
3283 return Some(make_sname_error());
3284 }
3285
3286 Some(make_forall_nat_syntax(&norm_motive))
3288}
3289
3290fn build_induction_step_formula(ctx: &Context, motive_body: &Term) -> Option<Term> {
3295 let p_k = motive_body.clone();
3297
3298 let succ_var = Term::App(
3300 Box::new(Term::App(
3301 Box::new(Term::Global("SApp".to_string())),
3302 Box::new(make_sname("Succ")),
3303 )),
3304 Box::new(Term::App(
3305 Box::new(Term::Global("SVar".to_string())),
3306 Box::new(Term::Lit(Literal::Int(0))),
3307 )),
3308 );
3309 let p_succ_k = try_syn_subst_reduce(ctx, &succ_var, 0, motive_body)?;
3310
3311 let implies_body = make_implies_syntax(&p_k, &p_succ_k);
3313
3314 let slam = Term::App(
3316 Box::new(Term::App(
3317 Box::new(Term::Global("SLam".to_string())),
3318 Box::new(make_sname("Nat")),
3319 )),
3320 Box::new(implies_body),
3321 );
3322
3323 Some(make_forall_syntax_with_type(&make_sname("Nat"), &slam))
3325}
3326
3327fn make_implies_syntax(a: &Term, b: &Term) -> Term {
3329 let app1 = Term::App(
3331 Box::new(Term::App(
3332 Box::new(Term::Global("SApp".to_string())),
3333 Box::new(make_sname("Implies")),
3334 )),
3335 Box::new(a.clone()),
3336 );
3337
3338 Term::App(
3340 Box::new(Term::App(
3341 Box::new(Term::Global("SApp".to_string())),
3342 Box::new(app1),
3343 )),
3344 Box::new(b.clone()),
3345 )
3346}
3347
3348fn make_forall_nat_syntax(motive: &Term) -> Term {
3350 make_forall_syntax_with_type(&make_sname("Nat"), motive)
3351}
3352
3353fn make_forall_syntax_with_type(type_s: &Term, body: &Term) -> Term {
3355 let app1 = Term::App(
3357 Box::new(Term::App(
3358 Box::new(Term::Global("SApp".to_string())),
3359 Box::new(make_sname("Forall")),
3360 )),
3361 Box::new(type_s.clone()),
3362 );
3363
3364 Term::App(
3366 Box::new(Term::App(
3367 Box::new(Term::Global("SApp".to_string())),
3368 Box::new(app1),
3369 )),
3370 Box::new(body.clone()),
3371 )
3372}
3373
3374fn try_dcompute_conclude(ctx: &Context, goal: &Term) -> Option<Term> {
3388 let norm_goal = normalize(ctx, goal);
3389
3390 let parts = extract_eq_syntax_parts(&norm_goal);
3393 if parts.is_none() {
3394 return Some(make_sname_error());
3396 }
3397 let (_, a, b) = parts.unwrap();
3398
3399 let fuel = 1000;
3401 let a_eval = match try_syn_eval_reduce(ctx, fuel, &a) {
3402 Some(e) => e,
3403 None => return Some(make_sname_error()),
3404 };
3405 let b_eval = match try_syn_eval_reduce(ctx, fuel, &b) {
3406 Some(e) => e,
3407 None => return Some(make_sname_error()),
3408 };
3409
3410 if syntax_equal(&a_eval, &b_eval) {
3412 Some(norm_goal)
3413 } else {
3414 Some(make_sname_error())
3415 }
3416}
3417
3418fn extract_eq_syntax_parts(term: &Term) -> Option<(Term, Term, Term)> {
3422 if let Term::App(partial2, b) = term {
3425 if let Term::App(sapp2, inner2) = partial2.as_ref() {
3426 if let Term::Global(sapp2_name) = sapp2.as_ref() {
3427 if sapp2_name != "SApp" {
3428 return None;
3429 }
3430 } else {
3431 return None;
3432 }
3433
3434 if let Term::App(partial1, a) = inner2.as_ref() {
3435 if let Term::App(sapp1, inner1) = partial1.as_ref() {
3436 if let Term::Global(sapp1_name) = sapp1.as_ref() {
3437 if sapp1_name != "SApp" {
3438 return None;
3439 }
3440 } else {
3441 return None;
3442 }
3443
3444 if let Term::App(eq_t, t) = inner1.as_ref() {
3445 if let Term::App(sapp0, eq_sname) = eq_t.as_ref() {
3446 if let Term::Global(sapp0_name) = sapp0.as_ref() {
3447 if sapp0_name != "SApp" {
3448 return None;
3449 }
3450 } else {
3451 return None;
3452 }
3453
3454 if let Term::App(sname_ctor, eq_str) = eq_sname.as_ref() {
3456 if let Term::Global(ctor) = sname_ctor.as_ref() {
3457 if ctor == "SName" {
3458 if let Term::Lit(Literal::Text(s)) = eq_str.as_ref() {
3459 if s == "Eq" {
3460 return Some((
3461 t.as_ref().clone(),
3462 a.as_ref().clone(),
3463 b.as_ref().clone(),
3464 ));
3465 }
3466 }
3467 }
3468 }
3469 }
3470 }
3471 }
3472 }
3473 }
3474 }
3475 }
3476 None
3477}
3478
3479fn try_tact_orelse_reduce(
3489 ctx: &Context,
3490 t1: &Term,
3491 t2: &Term,
3492 goal: &Term,
3493) -> Option<Term> {
3494 let norm_goal = normalize(ctx, goal);
3495
3496 let d1_app = Term::App(Box::new(t1.clone()), Box::new(norm_goal.clone()));
3498 let d1 = normalize(ctx, &d1_app);
3499
3500 if let Some(conc1) = try_concludes_reduce(ctx, &d1) {
3502 if is_error_syntax(&conc1) {
3503 let d2_app = Term::App(Box::new(t2.clone()), Box::new(norm_goal));
3505 return Some(normalize(ctx, &d2_app));
3506 } else {
3507 return Some(d1);
3509 }
3510 }
3511
3512 Some(make_error_derivation())
3514}
3515
3516fn is_error_syntax(term: &Term) -> bool {
3518 if let Term::App(ctor, arg) = term {
3520 if let Term::Global(name) = ctor.as_ref() {
3521 if name == "SName" {
3522 if let Term::Lit(Literal::Text(s)) = arg.as_ref() {
3523 return s == "Error";
3524 }
3525 }
3526 }
3527 }
3528 false
3529}
3530
3531fn try_tact_try_reduce(ctx: &Context, t: &Term, goal: &Term) -> Option<Term> {
3537 let norm_goal = normalize(ctx, goal);
3538
3539 let d_app = Term::App(Box::new(t.clone()), Box::new(norm_goal.clone()));
3541 let d = normalize(ctx, &d_app);
3542
3543 if let Some(conc) = try_concludes_reduce(ctx, &d) {
3545 if is_error_syntax(&conc) {
3546 return Some(make_daxiom(&norm_goal));
3548 } else {
3549 return Some(d);
3551 }
3552 }
3553
3554 Some(make_daxiom(&norm_goal))
3556}
3557
3558fn try_tact_repeat_reduce(ctx: &Context, t: &Term, goal: &Term) -> Option<Term> {
3563 const MAX_ITERATIONS: usize = 100;
3564
3565 let norm_goal = normalize(ctx, goal);
3566 let mut current_goal = norm_goal.clone();
3567 let mut last_successful_deriv: Option<Term> = None;
3568
3569 for _ in 0..MAX_ITERATIONS {
3570 let d_app = Term::App(Box::new(t.clone()), Box::new(current_goal.clone()));
3572 let d = normalize(ctx, &d_app);
3573
3574 if let Some(conc) = try_concludes_reduce(ctx, &d) {
3576 if is_error_syntax(&conc) {
3577 break;
3579 }
3580
3581 if syntax_equal(&conc, ¤t_goal) {
3583 break;
3585 }
3586
3587 current_goal = conc;
3589 last_successful_deriv = Some(d);
3590 } else {
3591 break;
3593 }
3594 }
3595
3596 last_successful_deriv.or_else(|| Some(make_daxiom(&norm_goal)))
3598}
3599
3600fn try_tact_then_reduce(
3606 ctx: &Context,
3607 t1: &Term,
3608 t2: &Term,
3609 goal: &Term,
3610) -> Option<Term> {
3611 let norm_goal = normalize(ctx, goal);
3612
3613 let d1_app = Term::App(Box::new(t1.clone()), Box::new(norm_goal.clone()));
3615 let d1 = normalize(ctx, &d1_app);
3616
3617 if let Some(conc1) = try_concludes_reduce(ctx, &d1) {
3619 if is_error_syntax(&conc1) {
3620 return Some(make_error_derivation());
3622 }
3623
3624 let d2_app = Term::App(Box::new(t2.clone()), Box::new(conc1));
3626 let d2 = normalize(ctx, &d2_app);
3627
3628 return Some(d2);
3630 }
3631
3632 Some(make_error_derivation())
3634}
3635
3636fn try_tact_first_reduce(ctx: &Context, tactics: &Term, goal: &Term) -> Option<Term> {
3641 let norm_goal = normalize(ctx, goal);
3642
3643 let tactic_vec = extract_tlist(tactics)?;
3645
3646 for tactic in tactic_vec {
3647 let d_app = Term::App(Box::new(tactic), Box::new(norm_goal.clone()));
3649 let d = normalize(ctx, &d_app);
3650
3651 if let Some(conc) = try_concludes_reduce(ctx, &d) {
3653 if !is_error_syntax(&conc) {
3654 return Some(d);
3656 }
3657 }
3659 }
3660
3661 Some(make_error_derivation())
3663}
3664
3665fn extract_tlist(term: &Term) -> Option<Vec<Term>> {
3672 let mut result = Vec::new();
3673 let mut current = term.clone();
3674
3675 loop {
3676 match ¤t {
3677 Term::App(tnil, _type) => {
3679 if let Term::Global(name) = tnil.as_ref() {
3680 if name == "TNil" {
3681 break;
3683 }
3684 }
3685 if let Term::App(partial2, tail) = ¤t {
3687 if let Term::App(partial1, head) = partial2.as_ref() {
3688 if let Term::App(tcons, _type) = partial1.as_ref() {
3689 if let Term::Global(name) = tcons.as_ref() {
3690 if name == "TCons" {
3691 result.push(head.as_ref().clone());
3692 current = tail.as_ref().clone();
3693 continue;
3694 }
3695 }
3696 }
3697 }
3698 }
3699 return None;
3701 }
3702 Term::Global(name) if name == "TNil" => {
3704 break;
3705 }
3706 _ => {
3707 return None;
3709 }
3710 }
3711 }
3712
3713 Some(result)
3714}
3715
3716fn try_tact_solve_reduce(ctx: &Context, t: &Term, goal: &Term) -> Option<Term> {
3722 let norm_goal = normalize(ctx, goal);
3723
3724 let d_app = Term::App(Box::new(t.clone()), Box::new(norm_goal.clone()));
3726 let d = normalize(ctx, &d_app);
3727
3728 if let Some(conc) = try_concludes_reduce(ctx, &d) {
3730 if is_error_syntax(&conc) {
3731 return Some(make_error_derivation());
3733 }
3734 return Some(d);
3736 }
3737
3738 Some(make_error_derivation())
3740}
3741
3742fn try_dcong_conclude(ctx: &Context, context: &Term, eq_proof: &Term) -> Option<Term> {
3753 let eq_conc = try_concludes_reduce(ctx, eq_proof)?;
3755
3756 let parts = extract_eq_syntax_parts(&eq_conc);
3758 if parts.is_none() {
3759 return Some(make_sname_error());
3761 }
3762 let (_type_term, lhs, rhs) = parts.unwrap();
3763
3764 let norm_context = normalize(ctx, context);
3766
3767 let slam_parts = extract_slam_parts(&norm_context);
3769 if slam_parts.is_none() {
3770 return Some(make_sname_error());
3772 }
3773 let (param_type, body) = slam_parts.unwrap();
3774
3775 let fa = try_syn_subst_reduce(ctx, &lhs, 0, &body)?;
3777 let fb = try_syn_subst_reduce(ctx, &rhs, 0, &body)?;
3778
3779 Some(make_eq_syntax_three(¶m_type, &fa, &fb))
3781}
3782
3783fn extract_slam_parts(term: &Term) -> Option<(Term, Term)> {
3787 if let Term::App(inner, body) = term {
3788 if let Term::App(slam_ctor, param_type) = inner.as_ref() {
3789 if let Term::Global(name) = slam_ctor.as_ref() {
3790 if name == "SLam" {
3791 return Some((param_type.as_ref().clone(), body.as_ref().clone()));
3792 }
3793 }
3794 }
3795 }
3796 None
3797}
3798
3799fn make_eq_syntax_three(type_s: &Term, a: &Term, b: &Term) -> Term {
3803 let eq_name = Term::App(
3804 Box::new(Term::Global("SName".to_string())),
3805 Box::new(Term::Lit(Literal::Text("Eq".to_string()))),
3806 );
3807
3808 let app1 = Term::App(
3810 Box::new(Term::App(
3811 Box::new(Term::Global("SApp".to_string())),
3812 Box::new(eq_name),
3813 )),
3814 Box::new(type_s.clone()),
3815 );
3816
3817 let app2 = Term::App(
3819 Box::new(Term::App(
3820 Box::new(Term::Global("SApp".to_string())),
3821 Box::new(app1),
3822 )),
3823 Box::new(a.clone()),
3824 );
3825
3826 Term::App(
3828 Box::new(Term::App(
3829 Box::new(Term::Global("SApp".to_string())),
3830 Box::new(app2),
3831 )),
3832 Box::new(b.clone()),
3833 )
3834}
3835
3836fn try_delim_conclude(
3852 ctx: &Context,
3853 ind_type: &Term,
3854 motive: &Term,
3855 cases: &Term,
3856) -> Option<Term> {
3857 let norm_ind_type = normalize(ctx, ind_type);
3859 let norm_motive = normalize(ctx, motive);
3860 let norm_cases = normalize(ctx, cases);
3861
3862 let ind_name = match extract_inductive_name_from_syntax(&norm_ind_type) {
3864 Some(name) => name,
3865 None => return Some(make_sname_error()),
3866 };
3867
3868 let constructors = ctx.get_constructors(&ind_name);
3870 if constructors.is_empty() {
3871 return Some(make_sname_error());
3873 }
3874
3875 let case_proofs = match extract_case_proofs(&norm_cases) {
3877 Some(proofs) => proofs,
3878 None => return Some(make_sname_error()),
3879 };
3880
3881 if case_proofs.len() != constructors.len() {
3883 return Some(make_sname_error());
3884 }
3885
3886 let motive_body = match extract_slam_body(&norm_motive) {
3888 Some(body) => body,
3889 None => return Some(make_sname_error()),
3890 };
3891
3892 for (i, (ctor_name, _ctor_type)) in constructors.iter().enumerate() {
3894 let case_proof = &case_proofs[i];
3895
3896 let case_conc = match try_concludes_reduce(ctx, case_proof) {
3898 Some(c) => c,
3899 None => return Some(make_sname_error()),
3900 };
3901
3902 let expected = match build_case_expected(ctx, ctor_name, &constructors, &motive_body, &norm_ind_type) {
3906 Some(e) => e,
3907 None => return Some(make_sname_error()),
3908 };
3909
3910 if !syntax_equal(&case_conc, &expected) {
3912 return Some(make_sname_error());
3913 }
3914 }
3915
3916 Some(make_forall_syntax_generic(&norm_ind_type, &norm_motive))
3918}
3919
3920fn extract_inductive_name_from_syntax(term: &Term) -> Option<String> {
3926 if let Term::App(sname, text) = term {
3928 if let Term::Global(ctor) = sname.as_ref() {
3929 if ctor == "SName" {
3930 if let Term::Lit(Literal::Text(name)) = text.as_ref() {
3931 return Some(name.clone());
3932 }
3933 }
3934 }
3935 }
3936
3937 if let Term::App(inner, _arg) = term {
3939 if let Term::App(sapp, func) = inner.as_ref() {
3940 if let Term::Global(ctor) = sapp.as_ref() {
3941 if ctor == "SApp" {
3942 return extract_inductive_name_from_syntax(func);
3944 }
3945 }
3946 }
3947 }
3948
3949 None
3950}
3951
3952fn extract_case_proofs(term: &Term) -> Option<Vec<Term>> {
3956 let mut proofs = Vec::new();
3957 let mut current = term;
3958
3959 loop {
3960 if let Term::Global(name) = current {
3962 if name == "DCaseEnd" {
3963 return Some(proofs);
3964 }
3965 }
3966
3967 if let Term::App(inner, tail) = current {
3969 if let Term::App(dcase, head) = inner.as_ref() {
3970 if let Term::Global(name) = dcase.as_ref() {
3971 if name == "DCase" {
3972 proofs.push(head.as_ref().clone());
3973 current = tail.as_ref();
3974 continue;
3975 }
3976 }
3977 }
3978 }
3979
3980 return None;
3982 }
3983}
3984
3985fn build_case_expected(
3990 ctx: &Context,
3991 ctor_name: &str,
3992 _constructors: &[(&str, &Term)],
3993 motive_body: &Term,
3994 ind_type: &Term,
3995) -> Option<Term> {
3996 let ind_name = extract_inductive_name_from_syntax(ind_type)?;
3998
3999 if ind_name == "Nat" {
4001 if ctor_name == "Zero" {
4002 let zero = make_sname("Zero");
4004 return try_syn_subst_reduce(ctx, &zero, 0, motive_body);
4005 } else if ctor_name == "Succ" {
4006 return build_induction_step_formula(ctx, motive_body);
4009 }
4010 }
4011
4012 let ctor_syntax = make_sname(ctor_name);
4015
4016 let ctor_applied = apply_type_args_to_ctor(&ctor_syntax, ind_type);
4019
4020 if let Some(ctor_ty) = ctx.get_global(ctor_name) {
4022 if is_recursive_constructor(ctx, ctor_ty, &ind_name, ind_type) {
4024 return build_recursive_case_formula(ctx, ctor_name, ctor_ty, motive_body, ind_type, &ind_name);
4026 }
4027 }
4028
4029 try_syn_subst_reduce(ctx, &ctor_applied, 0, motive_body)
4031}
4032
4033fn apply_type_args_to_ctor(ctor: &Term, ind_type: &Term) -> Term {
4038 let args = extract_type_args(ind_type);
4040
4041 if args.is_empty() {
4042 return ctor.clone();
4043 }
4044
4045 args.iter().fold(ctor.clone(), |acc, arg| {
4047 Term::App(
4048 Box::new(Term::App(
4049 Box::new(Term::Global("SApp".to_string())),
4050 Box::new(acc),
4051 )),
4052 Box::new(arg.clone()),
4053 )
4054 })
4055}
4056
4057fn extract_type_args(term: &Term) -> Vec<Term> {
4063 let mut args = Vec::new();
4064 let mut current = term;
4065
4066 loop {
4068 if let Term::App(inner, arg) = current {
4069 if let Term::App(sapp, func) = inner.as_ref() {
4070 if let Term::Global(ctor) = sapp.as_ref() {
4071 if ctor == "SApp" {
4072 args.push(arg.as_ref().clone());
4073 current = func.as_ref();
4074 continue;
4075 }
4076 }
4077 }
4078 }
4079 break;
4080 }
4081
4082 args.reverse();
4084 args
4085}
4086
4087fn make_forall_syntax_generic(ind_type: &Term, motive: &Term) -> Term {
4091 let forall_type = Term::App(
4093 Box::new(Term::App(
4094 Box::new(Term::Global("SApp".to_string())),
4095 Box::new(make_sname("Forall")),
4096 )),
4097 Box::new(ind_type.clone()),
4098 );
4099
4100 Term::App(
4102 Box::new(Term::App(
4103 Box::new(Term::Global("SApp".to_string())),
4104 Box::new(forall_type),
4105 )),
4106 Box::new(motive.clone()),
4107 )
4108}
4109
4110fn is_recursive_constructor(
4112 _ctx: &Context,
4113 ctor_ty: &Term,
4114 ind_name: &str,
4115 _ind_type: &Term,
4116) -> bool {
4117 fn contains_inductive(term: &Term, ind_name: &str) -> bool {
4122 match term {
4123 Term::Global(name) => name == ind_name,
4124 Term::App(f, a) => {
4125 contains_inductive(f, ind_name) || contains_inductive(a, ind_name)
4126 }
4127 Term::Pi { param_type, body_type, .. } => {
4128 contains_inductive(param_type, ind_name) || contains_inductive(body_type, ind_name)
4129 }
4130 Term::Lambda { param_type, body, .. } => {
4131 contains_inductive(param_type, ind_name) || contains_inductive(body, ind_name)
4132 }
4133 _ => false,
4134 }
4135 }
4136
4137 fn check_params(term: &Term, ind_name: &str) -> bool {
4139 match term {
4140 Term::Pi { param_type, body_type, .. } => {
4141 if contains_inductive(param_type, ind_name) {
4143 return true;
4144 }
4145 check_params(body_type, ind_name)
4147 }
4148 _ => false,
4149 }
4150 }
4151
4152 check_params(ctor_ty, ind_name)
4153}
4154
4155fn build_recursive_case_formula(
4161 ctx: &Context,
4162 ctor_name: &str,
4163 ctor_ty: &Term,
4164 motive_body: &Term,
4165 ind_type: &Term,
4166 ind_name: &str,
4167) -> Option<Term> {
4168 let type_args = extract_type_args(ind_type);
4170
4171 let args = collect_ctor_args(ctor_ty, ind_name, &type_args);
4173
4174 if args.is_empty() {
4175 let ctor_applied = apply_type_args_to_ctor(&make_sname(ctor_name), ind_type);
4177 return try_syn_subst_reduce(ctx, &ctor_applied, 0, motive_body);
4178 }
4179
4180 let mut ctor_app = apply_type_args_to_ctor(&make_sname(ctor_name), ind_type);
4188 for (i, _) in args.iter().enumerate() {
4189 let idx = (args.len() - 1 - i) as i64;
4191 let var = Term::App(
4192 Box::new(Term::Global("SVar".to_string())),
4193 Box::new(Term::Lit(Literal::Int(idx))),
4194 );
4195 ctor_app = Term::App(
4196 Box::new(Term::App(
4197 Box::new(Term::Global("SApp".to_string())),
4198 Box::new(ctor_app),
4199 )),
4200 Box::new(var),
4201 );
4202 }
4203
4204 let p_ctor = try_syn_subst_reduce(ctx, &ctor_app, 0, motive_body)?;
4206
4207 let mut body = p_ctor;
4209 for (i, (arg_ty, is_recursive)) in args.iter().enumerate().rev() {
4210 if *is_recursive {
4211 let idx = (args.len() - 1 - i) as i64;
4214 let var = Term::App(
4215 Box::new(Term::Global("SVar".to_string())),
4216 Box::new(Term::Lit(Literal::Int(idx))),
4217 );
4218 let p_arg = try_syn_subst_reduce(ctx, &var, 0, motive_body)?;
4219 body = make_implies_syntax(&p_arg, &body);
4220 }
4221 let _ = (i, arg_ty); }
4224
4225 for (arg_ty, _) in args.iter().rev() {
4227 let slam = Term::App(
4229 Box::new(Term::App(
4230 Box::new(Term::Global("SLam".to_string())),
4231 Box::new(arg_ty.clone()),
4232 )),
4233 Box::new(body.clone()),
4234 );
4235 body = make_forall_syntax_with_type(arg_ty, &slam);
4237 }
4238
4239 Some(body)
4240}
4241
4242fn collect_ctor_args(ctor_ty: &Term, ind_name: &str, type_args: &[Term]) -> Vec<(Term, bool)> {
4245 let mut args = Vec::new();
4246 let mut current = ctor_ty;
4247 let mut skip_count = type_args.len();
4248
4249 loop {
4250 match current {
4251 Term::Pi { param_type, body_type, .. } => {
4252 if skip_count > 0 {
4253 skip_count -= 1;
4255 } else {
4256 let is_recursive = contains_inductive_term(param_type, ind_name);
4258 let arg_ty_syntax = kernel_type_to_syntax(param_type);
4260 args.push((arg_ty_syntax, is_recursive));
4261 }
4262 current = body_type;
4263 }
4264 _ => break,
4265 }
4266 }
4267
4268 args
4269}
4270
4271fn contains_inductive_term(term: &Term, ind_name: &str) -> bool {
4273 match term {
4274 Term::Global(name) => name == ind_name,
4275 Term::App(f, a) => {
4276 contains_inductive_term(f, ind_name) || contains_inductive_term(a, ind_name)
4277 }
4278 Term::Pi { param_type, body_type, .. } => {
4279 contains_inductive_term(param_type, ind_name) || contains_inductive_term(body_type, ind_name)
4280 }
4281 Term::Lambda { param_type, body, .. } => {
4282 contains_inductive_term(param_type, ind_name) || contains_inductive_term(body, ind_name)
4283 }
4284 _ => false,
4285 }
4286}
4287
4288fn kernel_type_to_syntax(term: &Term) -> Term {
4290 match term {
4291 Term::Global(name) => make_sname(name),
4292 Term::Var(name) => make_sname(name), Term::App(f, a) => {
4294 let f_syn = kernel_type_to_syntax(f);
4295 let a_syn = kernel_type_to_syntax(a);
4296 Term::App(
4298 Box::new(Term::App(
4299 Box::new(Term::Global("SApp".to_string())),
4300 Box::new(f_syn),
4301 )),
4302 Box::new(a_syn),
4303 )
4304 }
4305 Term::Pi { param, param_type, body_type } => {
4306 let pt_syn = kernel_type_to_syntax(param_type);
4307 let bt_syn = kernel_type_to_syntax(body_type);
4308 Term::App(
4310 Box::new(Term::App(
4311 Box::new(Term::Global("SPi".to_string())),
4312 Box::new(pt_syn),
4313 )),
4314 Box::new(bt_syn),
4315 )
4316 }
4317 Term::Sort(univ) => {
4318 Term::App(
4320 Box::new(Term::Global("SSort".to_string())),
4321 Box::new(univ_to_syntax(univ)),
4322 )
4323 }
4324 Term::Lit(lit) => {
4325 Term::App(
4327 Box::new(Term::Global("SLit".to_string())),
4328 Box::new(Term::Lit(lit.clone())),
4329 )
4330 }
4331 _ => {
4332 make_sname("Unknown")
4334 }
4335 }
4336}
4337
4338fn univ_to_syntax(univ: &crate::term::Universe) -> Term {
4340 match univ {
4341 crate::term::Universe::Prop => Term::Global("UProp".to_string()),
4342 crate::term::Universe::Type(n) => Term::App(
4343 Box::new(Term::Global("UType".to_string())),
4344 Box::new(Term::Lit(Literal::Int(*n as i64))),
4345 ),
4346 }
4347}
4348
4349fn try_try_inversion_reduce(ctx: &Context, goal: &Term) -> Option<Term> {
4358 let (ind_name, hyp_args) = match extract_applied_inductive_from_syntax(goal) {
4360 Some((name, args)) => (name, args),
4361 None => return Some(make_error_derivation()),
4362 };
4363
4364 if !ctx.is_inductive(&ind_name) {
4366 return Some(make_error_derivation());
4368 }
4369
4370 let constructors = ctx.get_constructors(&ind_name);
4372
4373 let mut any_possible = false;
4375 for (_ctor_name, ctor_type) in constructors.iter() {
4376 if can_constructor_match_args(ctx, ctor_type, &hyp_args, &ind_name) {
4377 any_possible = true;
4378 break;
4379 }
4380 }
4381
4382 if any_possible {
4383 return Some(make_error_derivation());
4385 }
4386
4387 Some(Term::App(
4389 Box::new(Term::Global("DInversion".to_string())),
4390 Box::new(goal.clone()),
4391 ))
4392}
4393
4394fn try_dinversion_conclude(ctx: &Context, hyp_type: &Term) -> Option<Term> {
4396 let norm_hyp = normalize(ctx, hyp_type);
4397
4398 let (ind_name, hyp_args) = match extract_applied_inductive_from_syntax(&norm_hyp) {
4399 Some((name, args)) => (name, args),
4400 None => return Some(make_sname_error()),
4401 };
4402
4403 if !ctx.is_inductive(&ind_name) {
4405 return Some(make_sname_error());
4406 }
4407
4408 let constructors = ctx.get_constructors(&ind_name);
4409
4410 for (_ctor_name, ctor_type) in constructors.iter() {
4412 if can_constructor_match_args(ctx, ctor_type, &hyp_args, &ind_name) {
4413 return Some(make_sname_error());
4414 }
4415 }
4416
4417 Some(make_sname("False"))
4419}
4420
4421fn extract_applied_inductive_from_syntax(term: &Term) -> Option<(String, Vec<Term>)> {
4426 if let Term::App(ctor, text) = term {
4428 if let Term::Global(ctor_name) = ctor.as_ref() {
4429 if ctor_name == "SName" {
4430 if let Term::Lit(Literal::Text(name)) = text.as_ref() {
4431 return Some((name.clone(), vec![]));
4432 }
4433 }
4434 }
4435 }
4436
4437 if let Term::App(inner, arg) = term {
4439 if let Term::App(sapp_ctor, func) = inner.as_ref() {
4440 if let Term::Global(ctor_name) = sapp_ctor.as_ref() {
4441 if ctor_name == "SApp" {
4442 let (name, mut args) = extract_applied_inductive_from_syntax(func)?;
4444 args.push(arg.as_ref().clone());
4445 return Some((name, args));
4446 }
4447 }
4448 }
4449 }
4450
4451 None
4452}
4453
4454fn can_constructor_match_args(
4463 ctx: &Context,
4464 ctor_type: &Term,
4465 hyp_args: &[Term],
4466 ind_name: &str,
4467) -> bool {
4468 let (result, pattern_vars) = decompose_ctor_type_with_vars(ctor_type);
4470
4471 let result_args = match extract_applied_inductive_from_syntax(&kernel_type_to_syntax(&result)) {
4473 Some((name, args)) if name == *ind_name => args,
4474 _ => return false,
4475 };
4476
4477 if result_args.len() != hyp_args.len() {
4479 return false;
4480 }
4481
4482 let mut bindings: std::collections::HashMap<String, Term> = std::collections::HashMap::new();
4484
4485 for (pattern, concrete) in result_args.iter().zip(hyp_args.iter()) {
4486 if !can_unify_syntax_terms_with_bindings(ctx, pattern, concrete, &pattern_vars, &mut bindings) {
4487 return false;
4488 }
4489 }
4490
4491 true
4495}
4496
4497fn decompose_ctor_type_with_vars(ty: &Term) -> (Term, Vec<String>) {
4503 let mut vars = Vec::new();
4504 let mut current = ty;
4505 loop {
4506 match current {
4507 Term::Pi { param, body_type, .. } => {
4508 vars.push(param.clone());
4509 current = body_type;
4510 }
4511 _ => break,
4512 }
4513 }
4514 (current.clone(), vars)
4515}
4516
4517fn can_unify_syntax_terms_with_bindings(
4524 ctx: &Context,
4525 pattern: &Term,
4526 concrete: &Term,
4527 pattern_vars: &[String],
4528 bindings: &mut std::collections::HashMap<String, Term>,
4529) -> bool {
4530 if let Term::App(ctor, _idx) = pattern {
4532 if let Term::Global(name) = ctor.as_ref() {
4533 if name == "SVar" {
4534 return true;
4535 }
4536 }
4537 }
4538
4539 if let Term::App(ctor1, text1) = pattern {
4541 if let Term::Global(n1) = ctor1.as_ref() {
4542 if n1 == "SName" {
4543 if let Term::Lit(Literal::Text(var_name)) = text1.as_ref() {
4544 if pattern_vars.contains(var_name) {
4546 if let Some(existing) = bindings.get(var_name) {
4548 return syntax_terms_equal(existing, concrete);
4550 } else {
4551 bindings.insert(var_name.clone(), concrete.clone());
4553 return true;
4554 }
4555 }
4556 }
4557 if let Term::App(ctor2, text2) = concrete {
4559 if let Term::Global(n2) = ctor2.as_ref() {
4560 if n2 == "SName" {
4561 return text1 == text2;
4562 }
4563 }
4564 }
4565 return false;
4566 }
4567 }
4568 }
4569
4570 if let (Term::App(inner1, arg1), Term::App(inner2, arg2)) = (pattern, concrete) {
4572 if let (Term::App(sapp1, func1), Term::App(sapp2, func2)) =
4573 (inner1.as_ref(), inner2.as_ref())
4574 {
4575 if let (Term::Global(n1), Term::Global(n2)) = (sapp1.as_ref(), sapp2.as_ref()) {
4576 if n1 == "SApp" && n2 == "SApp" {
4577 return can_unify_syntax_terms_with_bindings(ctx, func1, func2, pattern_vars, bindings)
4578 && can_unify_syntax_terms_with_bindings(ctx, arg1.as_ref(), arg2.as_ref(), pattern_vars, bindings);
4579 }
4580 }
4581 }
4582 }
4583
4584 if let (Term::App(ctor1, lit1), Term::App(ctor2, lit2)) = (pattern, concrete) {
4586 if let (Term::Global(n1), Term::Global(n2)) = (ctor1.as_ref(), ctor2.as_ref()) {
4587 if n1 == "SLit" && n2 == "SLit" {
4588 return lit1 == lit2;
4589 }
4590 }
4591 }
4592
4593 pattern == concrete
4595}
4596
4597fn syntax_terms_equal(a: &Term, b: &Term) -> bool {
4599 match (a, b) {
4600 (Term::App(f1, x1), Term::App(f2, x2)) => {
4601 syntax_terms_equal(f1, f2) && syntax_terms_equal(x1, x2)
4602 }
4603 (Term::Global(n1), Term::Global(n2)) => n1 == n2,
4604 (Term::Lit(l1), Term::Lit(l2)) => l1 == l2,
4605 _ => a == b,
4606 }
4607}
4608
4609fn extract_eq_components_from_syntax(term: &Term) -> Option<(Term, Term, Term)> {
4617 let (eq_a_x, y) = extract_sapp(term)?;
4622
4623 let (eq_a, x) = extract_sapp(&eq_a_x)?;
4625
4626 let (eq, a) = extract_sapp(&eq_a)?;
4628
4629 let eq_name = extract_sname(&eq)?;
4631 if eq_name != "Eq" {
4632 return None;
4633 }
4634
4635 Some((a, x, y))
4636}
4637
4638fn extract_sapp(term: &Term) -> Option<(Term, Term)> {
4640 if let Term::App(inner, x) = term {
4642 if let Term::App(sapp_ctor, f) = inner.as_ref() {
4643 if let Term::Global(ctor_name) = sapp_ctor.as_ref() {
4644 if ctor_name == "SApp" {
4645 return Some((f.as_ref().clone(), x.as_ref().clone()));
4646 }
4647 }
4648 }
4649 }
4650 None
4651}
4652
4653fn extract_sname(term: &Term) -> Option<String> {
4655 if let Term::App(ctor, text) = term {
4656 if let Term::Global(ctor_name) = ctor.as_ref() {
4657 if ctor_name == "SName" {
4658 if let Term::Lit(Literal::Text(name)) = text.as_ref() {
4659 return Some(name.clone());
4660 }
4661 }
4662 }
4663 }
4664 None
4665}
4666
4667fn contains_subterm_syntax(term: &Term, target: &Term) -> bool {
4669 if syntax_equal(term, target) {
4670 return true;
4671 }
4672
4673 if let Some((f, x)) = extract_sapp(term) {
4675 if contains_subterm_syntax(&f, target) || contains_subterm_syntax(&x, target) {
4676 return true;
4677 }
4678 }
4679
4680 if let Some((t, body)) = extract_slam(term) {
4682 if contains_subterm_syntax(&t, target) || contains_subterm_syntax(&body, target) {
4683 return true;
4684 }
4685 }
4686
4687 if let Some((t, body)) = extract_spi(term) {
4689 if contains_subterm_syntax(&t, target) || contains_subterm_syntax(&body, target) {
4690 return true;
4691 }
4692 }
4693
4694 false
4695}
4696
4697fn extract_slam(term: &Term) -> Option<(Term, Term)> {
4699 if let Term::App(inner, body) = term {
4700 if let Term::App(slam_ctor, t) = inner.as_ref() {
4701 if let Term::Global(ctor_name) = slam_ctor.as_ref() {
4702 if ctor_name == "SLam" {
4703 return Some((t.as_ref().clone(), body.as_ref().clone()));
4704 }
4705 }
4706 }
4707 }
4708 None
4709}
4710
4711fn extract_spi(term: &Term) -> Option<(Term, Term)> {
4713 if let Term::App(inner, body) = term {
4714 if let Term::App(spi_ctor, t) = inner.as_ref() {
4715 if let Term::Global(ctor_name) = spi_ctor.as_ref() {
4716 if ctor_name == "SPi" {
4717 return Some((t.as_ref().clone(), body.as_ref().clone()));
4718 }
4719 }
4720 }
4721 }
4722 None
4723}
4724
4725fn replace_first_subterm_syntax(term: &Term, target: &Term, replacement: &Term) -> Option<Term> {
4727 if syntax_equal(term, target) {
4729 return Some(replacement.clone());
4730 }
4731
4732 if let Some((f, x)) = extract_sapp(term) {
4734 if let Some(new_f) = replace_first_subterm_syntax(&f, target, replacement) {
4736 return Some(make_sapp(new_f, x));
4737 }
4738 if let Some(new_x) = replace_first_subterm_syntax(&x, target, replacement) {
4740 return Some(make_sapp(f, new_x));
4741 }
4742 }
4743
4744 if let Some((t, body)) = extract_slam(term) {
4746 if let Some(new_t) = replace_first_subterm_syntax(&t, target, replacement) {
4747 return Some(make_slam(new_t, body));
4748 }
4749 if let Some(new_body) = replace_first_subterm_syntax(&body, target, replacement) {
4750 return Some(make_slam(t, new_body));
4751 }
4752 }
4753
4754 if let Some((t, body)) = extract_spi(term) {
4756 if let Some(new_t) = replace_first_subterm_syntax(&t, target, replacement) {
4757 return Some(make_spi(new_t, body));
4758 }
4759 if let Some(new_body) = replace_first_subterm_syntax(&body, target, replacement) {
4760 return Some(make_spi(t, new_body));
4761 }
4762 }
4763
4764 None
4766}
4767
4768fn try_try_rewrite_reduce(
4771 ctx: &Context,
4772 eq_proof: &Term,
4773 goal: &Term,
4774 reverse: bool,
4775) -> Option<Term> {
4776 let eq_conclusion = try_concludes_reduce(ctx, eq_proof)?;
4778
4779 let (ty, lhs, rhs) = match extract_eq_components_from_syntax(&eq_conclusion) {
4781 Some(components) => components,
4782 None => return Some(make_error_derivation()),
4783 };
4784
4785 let (target, replacement) = if reverse { (rhs, lhs) } else { (lhs, rhs) };
4787
4788 if !contains_subterm_syntax(goal, &target) {
4790 return Some(make_error_derivation());
4791 }
4792
4793 let new_goal = match replace_first_subterm_syntax(goal, &target, &replacement) {
4795 Some(ng) => ng,
4796 None => return Some(make_error_derivation()),
4797 };
4798
4799 Some(Term::App(
4801 Box::new(Term::App(
4802 Box::new(Term::App(
4803 Box::new(Term::Global("DRewrite".to_string())),
4804 Box::new(eq_proof.clone()),
4805 )),
4806 Box::new(goal.clone()),
4807 )),
4808 Box::new(new_goal),
4809 ))
4810}
4811
4812fn try_drewrite_conclude(
4814 ctx: &Context,
4815 eq_proof: &Term,
4816 old_goal: &Term,
4817 new_goal: &Term,
4818) -> Option<Term> {
4819 let eq_conclusion = try_concludes_reduce(ctx, eq_proof)?;
4821
4822 let (_ty, lhs, rhs) = match extract_eq_components_from_syntax(&eq_conclusion) {
4824 Some(components) => components,
4825 None => return Some(make_sname_error()),
4826 };
4827
4828 if let Some(computed_new) = replace_first_subterm_syntax(old_goal, &lhs, &rhs) {
4831 if syntax_equal(&computed_new, new_goal) {
4832 return Some(new_goal.clone());
4833 }
4834 }
4835
4836 if let Some(computed_new) = replace_first_subterm_syntax(old_goal, &rhs, &lhs) {
4838 if syntax_equal(&computed_new, new_goal) {
4839 return Some(new_goal.clone());
4840 }
4841 }
4842
4843 Some(make_sname_error())
4845}
4846
4847fn try_try_destruct_reduce(
4849 ctx: &Context,
4850 ind_type: &Term,
4851 motive: &Term,
4852 cases: &Term,
4853) -> Option<Term> {
4854 Some(Term::App(
4861 Box::new(Term::App(
4862 Box::new(Term::App(
4863 Box::new(Term::Global("DDestruct".to_string())),
4864 Box::new(ind_type.clone()),
4865 )),
4866 Box::new(motive.clone()),
4867 )),
4868 Box::new(cases.clone()),
4869 ))
4870}
4871
4872fn try_ddestruct_conclude(
4874 ctx: &Context,
4875 ind_type: &Term,
4876 motive: &Term,
4877 cases: &Term,
4878) -> Option<Term> {
4879 let ind_name = extract_inductive_name_from_syntax(ind_type)?;
4884
4885 if !ctx.is_inductive(&ind_name) {
4887 return Some(make_sname_error());
4888 }
4889
4890 let constructors = ctx.get_constructors(&ind_name);
4891
4892 let case_proofs = match extract_case_proofs(cases) {
4894 Some(proofs) => proofs,
4895 None => return Some(make_sname_error()),
4896 };
4897
4898 if case_proofs.len() != constructors.len() {
4900 return Some(make_sname_error());
4901 }
4902
4903 Some(make_forall_syntax_with_type(ind_type, motive))
4909}
4910
4911fn try_try_apply_reduce(
4913 ctx: &Context,
4914 hyp_name: &Term,
4915 hyp_proof: &Term,
4916 goal: &Term,
4917) -> Option<Term> {
4918 let hyp_conclusion = try_concludes_reduce(ctx, hyp_proof)?;
4920
4921 if let Some((antecedent, consequent)) = extract_spi(&hyp_conclusion) {
4923 if syntax_equal(&consequent, goal) {
4925 return Some(Term::App(
4927 Box::new(Term::App(
4928 Box::new(Term::App(
4929 Box::new(Term::App(
4930 Box::new(Term::Global("DApply".to_string())),
4931 Box::new(hyp_name.clone()),
4932 )),
4933 Box::new(hyp_proof.clone()),
4934 )),
4935 Box::new(goal.clone()),
4936 )),
4937 Box::new(antecedent),
4938 ));
4939 }
4940 }
4941
4942 if let Some(forall_body) = extract_forall_body(&hyp_conclusion) {
4944 return Some(Term::App(
4950 Box::new(Term::App(
4951 Box::new(Term::App(
4952 Box::new(Term::App(
4953 Box::new(Term::Global("DApply".to_string())),
4954 Box::new(hyp_name.clone()),
4955 )),
4956 Box::new(hyp_proof.clone()),
4957 )),
4958 Box::new(goal.clone()),
4959 )),
4960 Box::new(make_sname("True")),
4961 ));
4962 }
4963
4964 if syntax_equal(&hyp_conclusion, goal) {
4966 return Some(Term::App(
4967 Box::new(Term::App(
4968 Box::new(Term::App(
4969 Box::new(Term::App(
4970 Box::new(Term::Global("DApply".to_string())),
4971 Box::new(hyp_name.clone()),
4972 )),
4973 Box::new(hyp_proof.clone()),
4974 )),
4975 Box::new(goal.clone()),
4976 )),
4977 Box::new(make_sname("True")),
4978 ));
4979 }
4980
4981 Some(make_error_derivation())
4983}
4984
4985fn try_dapply_conclude(
4987 ctx: &Context,
4988 hyp_name: &Term,
4989 hyp_proof: &Term,
4990 old_goal: &Term,
4991 new_goal: &Term,
4992) -> Option<Term> {
4993 let hyp_conclusion = try_concludes_reduce(ctx, hyp_proof)?;
4995
4996 if let Some((antecedent, consequent)) = extract_spi(&hyp_conclusion) {
4999 if syntax_equal(&consequent, old_goal) {
5000 if syntax_equal(&antecedent, new_goal) || extract_sname(new_goal) == Some("True".to_string()) {
5001 return Some(new_goal.clone());
5002 }
5003 }
5004 }
5005
5006 if let Some(_forall_body) = extract_forall_body(&hyp_conclusion) {
5008 if extract_sname(new_goal) == Some("True".to_string()) {
5010 return Some(new_goal.clone());
5011 }
5012 }
5013
5014 if syntax_equal(&hyp_conclusion, old_goal) {
5016 if extract_sname(new_goal) == Some("True".to_string()) {
5017 return Some(new_goal.clone());
5018 }
5019 }
5020
5021 Some(make_sname_error())
5023}
5024