1use crate::context::Context;
44use crate::error::{KernelError, KernelResult};
45use crate::term::Term;
46
47fn g(n: &str) -> Term {
48 Term::Global(n.to_string())
49}
50fn v(n: &str) -> Term {
51 Term::Var(n.to_string())
52}
53fn app(f: Term, x: Term) -> Term {
54 Term::App(Box::new(f), Box::new(x))
55}
56fn apps(f: Term, xs: &[Term]) -> Term {
57 xs.iter().fold(f, |a, x| app(a, x.clone()))
58}
59fn lam(p: &str, t: Term, b: Term) -> Term {
60 Term::Lambda {
61 param: p.to_string(),
62 param_type: Box::new(t),
63 body: Box::new(b),
64 }
65}
66fn pi(p: &str, t: Term, b: Term) -> Term {
67 Term::Pi {
68 param: p.to_string(),
69 param_type: Box::new(t),
70 body_type: Box::new(b),
71 }
72}
73fn arrow(a: Term, b: Term) -> Term {
74 pi("_", a, b)
75}
76fn fix(name: &str, body: Term) -> Term {
77 Term::Fix {
78 name: name.to_string(),
79 body: Box::new(body),
80 }
81}
82fn mat(d: Term, motive: Term, cases: Vec<Term>) -> Term {
83 Term::Match {
84 discriminant: Box::new(d),
85 motive: Box::new(motive),
86 cases,
87 }
88}
89fn nat() -> Term {
90 g("Nat")
91}
92fn int() -> Term {
93 g("Int")
94}
95fn succ(t: Term) -> Term {
96 app(g("Succ"), t)
97}
98fn nat_motive() -> Term {
100 lam("_", nat(), nat())
101}
102fn int_motive() -> Term {
104 lam("_", int(), int())
105}
106fn nat_binop() -> Term {
107 arrow(nat(), arrow(nat(), nat()))
108}
109fn int_binop() -> Term {
110 arrow(int(), arrow(int(), int()))
111}
112fn of_nat(n: Term) -> Term {
113 app(g("Int_ofNat"), n)
114}
115fn neg_succ(n: Term) -> Term {
116 app(g("Int_negSucc"), n)
117}
118
119fn define_if_absent(ctx: &mut Context, name: &str, ty: Term, body: Term) {
122 if ctx.get_global(name).is_none() {
123 ctx.add_definition(name.to_string(), ty, body);
124 }
125}
126
127type ArithmeticDefinition = (&'static str, Term, Term);
135
136fn nat_arithmetic_definitions() -> &'static [ArithmeticDefinition] {
137 static DEFINITIONS: std::sync::OnceLock<Vec<ArithmeticDefinition>> = std::sync::OnceLock::new();
138 DEFINITIONS.get_or_init(|| {
139 let mut definitions = Vec::new();
140
141 definitions.push((
143 "Nat_add",
144 nat_binop(),
145 fix(
146 "f✧",
147 lam(
148 "m",
149 nat(),
150 lam(
151 "n",
152 nat(),
153 mat(
154 v("n"),
155 nat_motive(),
156 vec![
157 v("m"),
158 lam("k", nat(), succ(apps(v("f✧"), &[v("m"), v("k")]))),
159 ],
160 ),
161 ),
162 ),
163 ),
164 ));
165 definitions.push((
167 "Nat_pred",
168 arrow(nat(), nat()),
169 lam(
170 "x",
171 nat(),
172 mat(
173 v("x"),
174 nat_motive(),
175 vec![g("Zero"), lam("p", nat(), v("p"))],
176 ),
177 ),
178 ));
179 definitions.push((
181 "Nat_sub",
182 nat_binop(),
183 fix(
184 "f✧",
185 lam(
186 "m",
187 nat(),
188 lam(
189 "n",
190 nat(),
191 mat(
192 v("n"),
193 nat_motive(),
194 vec![
195 v("m"),
196 lam(
197 "k",
198 nat(),
199 app(g("Nat_pred"), apps(v("f✧"), &[v("m"), v("k")])),
200 ),
201 ],
202 ),
203 ),
204 ),
205 ),
206 ));
207 definitions.push((
209 "Nat_mul",
210 nat_binop(),
211 fix(
212 "f✧",
213 lam(
214 "m",
215 nat(),
216 lam(
217 "n",
218 nat(),
219 mat(
220 v("n"),
221 nat_motive(),
222 vec![
223 g("Zero"),
224 lam(
225 "k",
226 nat(),
227 apps(g("Nat_add"), &[apps(v("f✧"), &[v("m"), v("k")]), v("m")]),
228 ),
229 ],
230 ),
231 ),
232 ),
233 ),
234 ));
235
236 definitions
237 })
238}
239
240pub fn register_nat_arithmetic(ctx: &mut Context) {
241 for (name, ty, body) in nat_arithmetic_definitions() {
242 define_if_absent(ctx, name, ty.clone(), body.clone());
243 }
244}
245
246pub fn register_int_constructors(ctx: &mut Context) -> KernelResult<()> {
252 if !ctx.is_inductive("Int") {
253 return Err(KernelError::CertificationError(
254 "`Int` must already be a registered inductive — this adds its constructors, it does \
255 not declare the carrier"
256 .to_string(),
257 ));
258 }
259 if !ctx.get_constructors("Int").is_empty() {
260 return Ok(());
261 }
262 ctx.add_constructor_checked("Int_ofNat", "Int", arrow(nat(), int()))?;
263 ctx.add_constructor_checked("Int_negSucc", "Int", arrow(nat(), int()))?;
264 Ok(())
265}
266
267fn int_arithmetic_definitions() -> &'static [ArithmeticDefinition] {
288 static DEFINITIONS: std::sync::OnceLock<Vec<ArithmeticDefinition>> = std::sync::OnceLock::new();
289 DEFINITIONS.get_or_init(|| {
290 let mut definitions = Vec::new();
291 let nadd = |a: Term, b: Term| apps(g("Nat_add"), &[a, b]);
292 let nmul = |a: Term, b: Term| apps(g("Nat_mul"), &[a, b]);
293
294 definitions.push((
296 "Int_negOfNat",
297 arrow(nat(), int()),
298 lam(
299 "n",
300 nat(),
301 mat(
302 v("n"),
303 lam("_", nat(), int()),
304 vec![of_nat(g("Zero")), lam("k", nat(), neg_succ(v("k")))],
305 ),
306 ),
307 ));
308 definitions.push((
310 "Int_subNatNat",
311 arrow(nat(), arrow(nat(), int())),
312 lam(
313 "m",
314 nat(),
315 lam(
316 "n",
317 nat(),
318 mat(
319 apps(g("Nat_sub"), &[v("n"), v("m")]),
320 lam("_", nat(), int()),
321 vec![
322 of_nat(apps(g("Nat_sub"), &[v("m"), v("n")])),
323 lam("k", nat(), neg_succ(v("k"))),
324 ],
325 ),
326 ),
327 ),
328 ));
329 definitions.push((
331 "Int_neg",
332 arrow(int(), int()),
333 lam(
334 "a",
335 int(),
336 mat(
337 v("a"),
338 int_motive(),
339 vec![
340 lam("m", nat(), app(g("Int_negOfNat"), v("m"))),
341 lam("m", nat(), of_nat(succ(v("m")))),
342 ],
343 ),
344 ),
345 ));
346 definitions.push((
348 "Int_add",
349 int_binop(),
350 lam(
351 "a",
352 int(),
353 lam(
354 "b",
355 int(),
356 mat(
357 v("a"),
358 int_motive(),
359 vec![
360 lam(
361 "m",
362 nat(),
363 mat(
364 v("b"),
365 int_motive(),
366 vec![
367 lam("n", nat(), of_nat(nadd(v("m"), v("n")))),
368 lam(
369 "n",
370 nat(),
371 apps(g("Int_subNatNat"), &[v("m"), succ(v("n"))]),
372 ),
373 ],
374 ),
375 ),
376 lam(
377 "m",
378 nat(),
379 mat(
380 v("b"),
381 int_motive(),
382 vec![
383 lam(
384 "n",
385 nat(),
386 apps(g("Int_subNatNat"), &[v("n"), succ(v("m"))]),
387 ),
388 lam("n", nat(), neg_succ(succ(nadd(v("m"), v("n"))))),
389 ],
390 ),
391 ),
392 ],
393 ),
394 ),
395 ),
396 ));
397 definitions.push((
400 "Int_sub",
401 int_binop(),
402 lam(
403 "a",
404 int(),
405 lam(
406 "b",
407 int(),
408 apps(g("Int_add"), &[v("a"), app(g("Int_neg"), v("b"))]),
409 ),
410 ),
411 ));
412 definitions.push((
414 "Int_mul",
415 int_binop(),
416 lam(
417 "a",
418 int(),
419 lam(
420 "b",
421 int(),
422 mat(
423 v("a"),
424 int_motive(),
425 vec![
426 lam(
427 "m",
428 nat(),
429 mat(
430 v("b"),
431 int_motive(),
432 vec![
433 lam("n", nat(), of_nat(nmul(v("m"), v("n")))),
434 lam(
435 "n",
436 nat(),
437 app(g("Int_negOfNat"), nmul(v("m"), succ(v("n")))),
438 ),
439 ],
440 ),
441 ),
442 lam(
443 "m",
444 nat(),
445 mat(
446 v("b"),
447 int_motive(),
448 vec![
449 lam(
450 "n",
451 nat(),
452 app(g("Int_negOfNat"), nmul(succ(v("m")), v("n"))),
453 ),
454 lam("n", nat(), of_nat(nmul(succ(v("m")), succ(v("n"))))),
455 ],
456 ),
457 ),
458 ],
459 ),
460 ),
461 ),
462 ));
463
464 definitions
465 })
466}
467
468pub fn register_int_arithmetic(ctx: &mut Context) -> KernelResult<()> {
469 if ctx.get_constructors("Int").len() != 2 {
470 return Err(KernelError::CertificationError(
471 "`Int`'s arithmetic is defined BY CASES on `ofNat`/`negSucc` — register the \
472 constructors first"
473 .to_string(),
474 ));
475 }
476 register_nat_arithmetic(ctx);
477 for (name, ty, body) in int_arithmetic_definitions() {
478 define_if_absent(ctx, name, ty.clone(), body.clone());
479 }
480 Ok(())
481}
482
483pub fn register_inductive_int(ctx: &mut Context) -> KernelResult<()> {
504 register_int_constructors(ctx)?;
505 register_int_arithmetic(ctx)
506}
507
508pub fn canonical_int(n: i64) -> Term {
512 canonical_bigint(&crate::BigInt::from_i64(n))
513}
514
515pub(crate) fn canonical_environment(ctx: &Context) -> bool {
518 ctx.canonical_numerals().int
519}
520
521pub(crate) fn canonical_nat_environment(ctx: &Context) -> bool {
524 ctx.canonical_numerals().nat
525}
526
527pub(crate) fn reads_nat_literal(ctx: &Context, n: &crate::BigInt) -> bool {
531 let numerals = ctx.canonical_numerals();
532 if *n <= crate::BigInt::from_i64(0) {
533 numerals.zero
534 } else {
535 numerals.succ
536 }
537}
538
539pub(crate) fn canonical_numerals_of(ctx: &Context) -> crate::context::CanonicalNumerals {
542 let nat = canonical_family_environment(ctx, "Nat", ["Zero", "Succ"]);
543 let zero = nat || nat_constructor_environment(ctx, "Zero", &|ty| *ty == g("Nat"));
544 let unary = |ty: &Term| {
545 matches!(ty, Term::Pi { param_type, body_type, .. }
546 if **param_type == g("Nat") && **body_type == g("Nat"))
547 };
548 crate::context::CanonicalNumerals {
549 zero,
550 succ: nat || (zero && nat_constructor_environment(ctx, "Succ", &unary)),
551 nat,
552 int: nat && canonical_family_environment(ctx, "Int", ["Int_ofNat", "Int_negSucc"]),
553 }
554}
555
556fn nat_constructor_environment(ctx: &Context, name: &str, fits: &dyn Fn(&Term) -> bool) -> bool {
559 use crate::Universe;
560 ctx.is_inductive("Nat")
561 && ctx.get_global("Nat") == Some(&Term::Sort(Universe::Type(0)))
562 && ctx.inductive_num_params("Nat") == 0
563 && ctx.poly_declaration("Nat").is_none()
564 && ctx.get_definition_body("Nat").is_none()
565 && ctx.constructor_inductive(name) == Some("Nat")
566 && ctx.get_global(name).is_some_and(fits)
567 && ctx.poly_declaration(name).is_none()
568 && ctx.get_definition_body(name).is_none()
569}
570
571fn canonical_family_environment(ctx: &Context, family: &str, names: [&str; 2]) -> bool {
572 use crate::{Term, Universe};
573 if !ctx.is_inductive(family)
574 || ctx.get_global(family) != Some(&Term::Sort(Universe::Type(0)))
575 || ctx.inductive_num_params(family) != 0
576 || ctx.poly_declaration(family).is_some()
577 || ctx.get_definition_body(family).is_some()
578 {
579 return false;
580 }
581 let constructors = ctx.get_constructors(family);
582 if constructors.len() != 2 {
583 return false;
584 }
585 for ((actual, ty), expected) in constructors.iter().zip(names) {
586 if *actual != expected
587 || ctx.constructor_inductive(expected) != Some(family)
588 || ctx.get_global(expected) != Some(*ty)
589 || ctx.poly_declaration(expected).is_some()
590 || ctx.get_definition_body(expected).is_some()
591 {
592 return false;
593 }
594 let right_type = if expected == "Zero" {
595 **ty == g("Nat")
596 } else {
597 matches!(ty, Term::Pi { param_type, body_type, .. }
598 if **param_type == g("Nat") && **body_type == g(family))
599 };
600 if !right_type {
601 return false;
602 }
603 }
604 true
605}
606
607pub(crate) fn literal_constructor(ctx: &Context, t: &Term) -> Option<Term> {
609 let Term::Lit(literal) = t else { return None };
610 let n = crate::term::lit_bigint(literal)?;
611 if !canonical_environment(ctx) {
612 return None;
613 }
614 Some(canonical_bigint(&n))
615}
616
617fn canonical_bigint(n: &crate::BigInt) -> Term {
618 use crate::{BigInt, Literal};
619 if n.is_negative() {
620 neg_succ(Term::Lit(Literal::Nat(n.abs().sub(&BigInt::from_i64(1)))))
621 } else {
622 of_nat(Term::Lit(Literal::Nat(n.clone())))
623 }
624}
625
626pub(crate) fn constructor_literal(ctx: &Context, t: &Term) -> Option<crate::Literal> {
629 let Term::App(head, field) = t else {
630 return None;
631 };
632 let negative = match head.as_ref() {
633 Term::Global(n) if n == "Int_ofNat" => false,
634 Term::Global(n) if n == "Int_negSucc" => true,
635 _ => return None,
636 };
637 if !canonical_environment(ctx) {
638 return None;
639 }
640 let mut field = field.as_ref();
641 let mut count = crate::BigInt::from_i64(0);
642 let one = crate::BigInt::from_i64(1);
643 loop {
644 match field {
645 Term::Lit(crate::Literal::Nat(n)) if !n.is_negative() => {
646 count = count.add(n);
647 break;
648 }
649 Term::Global(n) if n == "Zero" => break,
650 Term::App(f, a) if matches!(f.as_ref(), Term::Global(n) if n == "Succ") => {
651 count = count.add(&one);
652 field = a;
653 }
654 _ => return None,
655 }
656 }
657 if negative {
658 count = count.add(&one).negated();
659 }
660 Some(crate::term::int_lit(count))
661}
662
663fn integer_order_definition() -> &'static ArithmeticDefinition {
666 static DEFINITION: std::sync::OnceLock<ArithmeticDefinition> = std::sync::OnceLock::new();
667 DEFINITION.get_or_init(|| {
668 let bool_motive = || lam("_", int(), g("Bool"));
669 let body = lam(
670 "a",
671 int(),
672 lam(
673 "b",
674 int(),
675 mat(
676 v("a"),
677 bool_motive(),
678 vec![
679 lam(
680 "m",
681 nat(),
682 mat(
683 v("b"),
684 bool_motive(),
685 vec![
686 lam("n", nat(), apps(g("natLe"), &[v("m"), v("n")])),
687 lam("n", nat(), g("false")),
688 ],
689 ),
690 ),
691 lam(
692 "m",
693 nat(),
694 mat(
695 v("b"),
696 bool_motive(),
697 vec![
698 lam("n", nat(), g("true")),
699 lam("n", nat(), apps(g("natLe"), &[v("n"), v("m")])),
700 ],
701 ),
702 ),
703 ],
704 ),
705 ),
706 );
707 ("Int_le", arrow(int(), arrow(int(), g("Bool"))), body)
708 })
709}
710
711pub(crate) fn register_public_order_alias(ctx: &mut Context) -> KernelResult<()> {
714 let (name, ty, body) = integer_order_definition();
715 ctx.declare_checked_auxiliary(name, ty.clone(), body.clone())?;
716 let public_type = ctx.get_global("le").cloned().unwrap_or_else(|| ty.clone());
717 ctx.declare_checked_auxiliary("le", public_type, g(name))?;
718 Ok(())
719}
720
721fn has_integer_binop_signature(ty: &Term) -> bool {
725 has_integer_binary_result(ty, "Int")
726}
727
728fn has_integer_binary_result(ty: &Term, result_name: &str) -> bool {
729 let Term::Pi {
730 param_type: first,
731 body_type: rest,
732 ..
733 } = ty
734 else {
735 return false;
736 };
737 let Term::Pi {
738 param_type: second,
739 body_type: result,
740 ..
741 } = rest.as_ref()
742 else {
743 return false;
744 };
745 [first.as_ref(), second.as_ref()]
746 .into_iter()
747 .all(|part| matches!(part, Term::Global(name) if name == "Int"))
748 && matches!(result.as_ref(), Term::Global(name) if name == result_name)
749}
750
751fn integer_division_definitions() -> &'static [ArithmeticDefinition] {
752 static DEFINITIONS: std::sync::OnceLock<Vec<ArithmeticDefinition>> = std::sync::OnceLock::new();
753 DEFINITIONS.get_or_init(|| {
754 let pair_ty = || apps(g("Prod"), &[int(), int()]);
755 let pair = |q: Term, r: Term| apps(g("Prod_mk"), &[int(), int(), q, r]);
756 let natural_pair = || apps(g("Prod"), &[nat(), nat()]);
757 let nonzero = |negative_divisor: bool| {
758 let positive = mat(
759 apps(g("Nat_divMod"), &[v("m"), succ(v("k"))]),
760 lam("_", natural_pair(), pair_ty()),
761 vec![lam(
762 "q",
763 nat(),
764 lam(
765 "r",
766 nat(),
767 pair(
768 if negative_divisor {
769 app(g("Int_negOfNat"), v("q"))
770 } else {
771 of_nat(v("q"))
772 },
773 of_nat(v("r")),
774 ),
775 ),
776 )],
777 );
778 let negative = mat(
779 apps(g("Nat_divMod"), &[succ(v("m")), succ(v("k"))]),
780 lam("_", natural_pair(), pair_ty()),
781 vec![lam(
782 "q",
783 nat(),
784 lam(
785 "r",
786 nat(),
787 mat(
788 v("r"),
789 lam("_", nat(), pair_ty()),
790 vec![
791 pair(
792 if negative_divisor {
793 of_nat(v("q"))
794 } else {
795 app(g("Int_negOfNat"), v("q"))
796 },
797 of_nat(g("Zero")),
798 ),
799 lam(
800 "s",
801 nat(),
802 pair(
803 if negative_divisor {
804 of_nat(succ(v("q")))
805 } else {
806 neg_succ(v("q"))
807 },
808 of_nat(apps(g("Nat_sub"), &[succ(v("k")), succ(v("s"))])),
809 ),
810 ),
811 ],
812 ),
813 ),
814 )],
815 );
816 mat(
817 v("a"),
818 lam("_", int(), pair_ty()),
819 vec![lam("m", nat(), positive), lam("m", nat(), negative)],
820 )
821 };
822 let body = lam(
823 "a",
824 int(),
825 lam(
826 "b",
827 int(),
828 mat(
829 v("b"),
830 lam("_", int(), pair_ty()),
831 vec![
832 lam(
833 "n",
834 nat(),
835 mat(
836 v("n"),
837 lam("_", nat(), pair_ty()),
838 vec![
839 pair(of_nat(g("Zero")), v("a")),
840 lam("k", nat(), nonzero(false)),
841 ],
842 ),
843 ),
844 lam("k", nat(), nonzero(true)),
845 ],
846 ),
847 ),
848 );
849 let mut definitions = vec![("Int_divMod", arrow(int(), arrow(int(), pair_ty())), body)];
850 for (name, projection) in [("Int_div", "Prod_fst"), ("Int_mod", "Prod_snd")] {
851 definitions.push((
852 name,
853 int_binop(),
854 lam(
855 "a",
856 int(),
857 lam(
858 "b",
859 int(),
860 apps(
861 g(projection),
862 &[int(), int(), apps(g("Int_divMod"), &[v("a"), v("b")])],
863 ),
864 ),
865 ),
866 ));
867 }
868 definitions
869 })
870}
871
872pub(crate) fn register_public_division_aliases(ctx: &mut Context) -> KernelResult<()> {
873 for (name, ty, body) in integer_division_definitions() {
874 ctx.declare_checked_auxiliary(name, ty.clone(), body.clone())?;
875 }
876 for (name, target) in [("div", "Int_div"), ("mod", "Int_mod")] {
877 let ty = ctx.get_global(name).cloned().unwrap_or_else(int_binop);
878 ctx.declare_checked_auxiliary(name, ty, g(target))?;
879 }
880 Ok(())
881}
882
883fn canonical_division_products(ctx: &Context) -> bool {
886 let reference = crate::prelude::StandardLibrary::division_carrier_reference();
887 for family in ["Bool", "Prod"] {
888 if !ctx.is_inductive(family)
889 || ctx.get_global(family) != reference.get_global(family)
890 || ctx.inductive_num_params(family) != reference.inductive_num_params(family)
891 || ctx.poly_declaration(family).is_some()
892 || ctx.get_definition_body(family).is_some()
893 {
894 return false;
895 }
896 let actual = ctx.get_constructors(family);
897 let expected = reference.get_constructors(family);
898 if actual != expected {
899 return false;
900 }
901 for (name, ty) in expected {
902 if ctx.constructor_inductive(name) != Some(family)
903 || ctx.get_global(name) != Some(ty)
904 || ctx.poly_declaration(name).is_some()
905 || ctx.get_definition_body(name).is_some()
906 {
907 return false;
908 }
909 }
910 }
911 ["Prod_fst", "Prod_snd"].into_iter().all(|name| {
912 ctx.poly_declaration(name).is_none()
913 && !ctx.is_constructor(name)
914 && !ctx.is_inductive(name)
915 && ctx.get_global(name) == reference.get_global(name)
916 && ctx.get_definition_type(name) == reference.get_definition_type(name)
917 && ctx.get_definition_body(name) == reference.get_definition_body(name)
918 })
919}
920
921pub(crate) fn integer_alias_dependencies(operation: &str) -> Option<&'static [&'static str]> {
923 match operation {
924 "add" => Some(&[
925 "add",
926 "Int_add",
927 "Int_subNatNat",
928 "Nat_sub",
929 "Nat_pred",
930 "Nat_add",
931 ]),
932 "mul" => Some(&["mul", "Int_mul", "Int_negOfNat", "Nat_mul", "Nat_add"]),
933 "sub" => Some(&[
934 "sub",
935 "Int_sub",
936 "Int_neg",
937 "Int_negOfNat",
938 "Int_add",
939 "Int_subNatNat",
940 "Nat_sub",
941 "Nat_pred",
942 "Nat_add",
943 ]),
944 "le" => Some(&["le", "Int_le", "natLe"]),
945 "div" => Some(&[
946 "div",
947 "Int_div",
948 "Int_divMod",
949 "Prod_fst",
950 "Prod_snd",
951 "Nat_divMod",
952 "Nat_divModSucc",
953 "Nat_sub",
954 "Nat_pred",
955 "Int_negOfNat",
956 "natLt",
957 "natLe",
958 ]),
959 "mod" => Some(&[
960 "mod",
961 "Int_mod",
962 "Int_divMod",
963 "Prod_fst",
964 "Prod_snd",
965 "Nat_divMod",
966 "Nat_divModSucc",
967 "Nat_sub",
968 "Nat_pred",
969 "Int_negOfNat",
970 "natLt",
971 "natLe",
972 ]),
973 _ => None,
974 }
975}
976
977pub(crate) fn accelerates_integer_alias(ctx: &Context, operation: &str) -> bool {
982 if !ctx.simp_rules().is_empty() {
983 return false;
984 }
985 let Some(dependencies) = integer_alias_dependencies(operation) else {
986 return false;
987 };
988 ctx.cached_integer_arithmetic(operation, || {
989 if !canonical_environment(ctx)
990 || !canonical_nat_environment(ctx)
991 || ctx.inductive_num_params("Nat") != 0
992 || ctx.inductive_num_params("Int") != 0
993 {
994 return false;
995 }
996 for name in ["Nat", "Zero", "Succ", "Int", "Int_ofNat", "Int_negSucc"] {
997 if ctx.poly_declaration(name).is_some() {
998 return false;
999 }
1000 }
1001 let target = match operation {
1002 "add" => "Int_add",
1003 "mul" => "Int_mul",
1004 "sub" => "Int_sub",
1005 "le" => "Int_le",
1006 "div" => "Int_div",
1007 "mod" => "Int_mod",
1008 _ => return false,
1009 };
1010 let has_signature = |ty: &Term| {
1011 if operation == "le" {
1012 has_integer_binary_result(ty, "Bool")
1013 } else {
1014 has_integer_binop_signature(ty)
1015 }
1016 };
1017 if ctx.poly_declaration(operation).is_some()
1018 || ctx.is_constructor(operation)
1019 || ctx.is_inductive(operation)
1020 || !ctx.get_global(operation).is_some_and(has_signature)
1021 || ctx.get_definition_body(operation) != Some(&g(target))
1022 || !ctx
1023 .get_definition_type(operation)
1024 .is_some_and(has_signature)
1025 {
1026 return false;
1027 }
1028 if operation == "le" {
1029 let (_, ty, body) = integer_order_definition();
1030 return ctx.poly_declaration("Int_le").is_none()
1031 && !ctx.is_constructor("Int_le")
1032 && !ctx.is_inductive("Int_le")
1033 && ctx.get_global("Int_le") == Some(ty)
1034 && ctx.get_definition_type("Int_le") == Some(ty)
1035 && ctx.get_definition_body("Int_le") == Some(body)
1036 && ctx.poly_declaration("natLe").is_none()
1037 && !ctx.is_constructor("natLe")
1038 && !ctx.is_inductive("natLe")
1039 && ctx.get_global("natLe") == ctx.get_definition_type("natLe")
1040 && crate::reduction::accelerates_nat_order(ctx, "natLe");
1041 }
1042 let division = matches!(operation, "div" | "mod");
1043 if division && !canonical_division_products(ctx) {
1044 return false;
1045 }
1046 dependencies[1..].iter().all(|name| {
1047 if division && matches!(*name, "Prod_fst" | "Prod_snd") {
1048 return true; }
1050 if division && matches!(*name, "natLt" | "natLe") {
1051 return ctx.poly_declaration(name).is_none()
1052 && !ctx.is_constructor(name)
1053 && !ctx.is_inductive(name)
1054 && ctx.get_global(name) == ctx.get_definition_type(name)
1055 && crate::reduction::accelerates_nat_order(ctx, name);
1056 }
1057 let Some((_, ty, body)) = nat_arithmetic_definitions()
1058 .iter()
1059 .chain(int_arithmetic_definitions())
1060 .chain(integer_division_definitions())
1061 .chain(crate::prelude::natural_arithmetic::division_definitions())
1062 .find(|(candidate, _, _)| candidate == name)
1063 else {
1064 return false;
1065 };
1066 ctx.poly_declaration(name).is_none()
1067 && !ctx.is_constructor(name)
1068 && !ctx.is_inductive(name)
1069 && ctx.get_global(name) == Some(ty)
1070 && ctx.get_definition_type(name) == Some(ty)
1071 && ctx.get_definition_body(name) == Some(body)
1072 })
1073 })
1074}
1075
1076pub fn supports_integer_polynomial_operations(ctx: &Context) -> bool {
1084 accelerates_integer_alias(ctx, "add")
1085 && accelerates_integer_alias(ctx, "mul")
1086 && accelerates_integer_alias(ctx, "sub")
1087}
1088
1089pub(crate) fn register_public_arithmetic_aliases(ctx: &mut Context) -> KernelResult<()> {
1092 for (name, target) in [("add", "Int_add"), ("mul", "Int_mul"), ("sub", "Int_sub")] {
1093 ctx.declare(name, int_binop(), g(target))?;
1094 }
1095 Ok(())
1096}
1097
1098#[cfg(test)]
1099#[path = "../../logicaffeine_tests/unit/logicaffeine_kernel/int_inductive/checked_alias_attestation_controls.rs"]
1100mod checked_alias_attestation_controls;
1101
1102#[cfg(test)]
1103#[path = "../../logicaffeine_tests/unit/logicaffeine_kernel/int_inductive/alias_visible_header_control.rs"]
1104mod alias_visible_header_control;
1105
1106#[cfg(test)]
1107#[path = "../../logicaffeine_tests/unit/logicaffeine_kernel/int_inductive/subtraction_alias_adversaries.rs"]
1108mod subtraction_alias_adversaries;
1109
1110#[cfg(test)]
1111#[path = "../../logicaffeine_tests/unit/logicaffeine_kernel/int_inductive/integer_alias_signature_controls.rs"]
1112mod integer_alias_signature_controls;
1113
1114#[cfg(test)]
1115#[path = "../../logicaffeine_tests/unit/logicaffeine_kernel/int_inductive/checked_order_alias_adversaries.rs"]
1116mod checked_order_alias_adversaries;
1117
1118#[cfg(test)]
1119#[path = "../../logicaffeine_tests/unit/logicaffeine_kernel/int_inductive/checked_division_attestation_controls.rs"]
1120mod checked_division_attestation_controls;