package rocq-runtime
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
The Rocq Prover -- Core Binaries and Tools
Install
dune-project
Dependency
Authors
Maintainers
Sources
rocq-9.2.0.tar.gz
sha256=a45280ab4fbaac7540b136a6b073b4a6db15739ec1e149bded43fa6f4fc25f20
doc/src/rocq-runtime.tactics/allScheme.ml.html
Source file allScheme.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************) open Declarations open Util open Names open Nameops open Constr open Vars open Environ open Reduction open Context.Rel.Declaration (** Generalize parameters for template and univ poly, and split uniform and non-uniform parameters *) let split_uparans_nuparams mib params = let (uparams, nuparams) = Context.Rel.chop_nhyps mib.mind_nparams_rec (List.rev params) in (List.rev uparams, List.rev nuparams) (** {6 Strictly Positive Uniform Parameters } *) let dbg_strpos = CDebug.create ~name:"strpos" () let pp_strpos l = Pp.(str "[" ++ prlist_with_sep (fun () -> str ";" ++ spc()) bool l ++ str "]") (** Iterate [&&] on [f x] for an array [ar] *) let andl_array f default ar = Array.fold_right (fun x acc -> (List.map2 (&&)) acc (f x)) ar default (** Check which uniform parameters are arity, unfolding Let-ins, and returns the updated environment and the initial value of strictly positivity *) let init_value env uparams = let rec aux env (tel : Constr.rel_context) = match tel with | [] -> (env, []) | decl::tel -> match get_value decl with | Some _ -> aux (push_rel decl env) tel | None -> let (env, init_value) = aux (push_rel decl env) tel in (env, Reduction.is_arity env (get_type decl) :: init_value) in aux env (List.rev uparams) (** Check if the uniform parameters appear in a term *) let check_strpos env uparams t = let nenv = List.length @@ Environ.rel_context env in let rec aux i tel = match tel with | [] -> [] | decl::tel -> match get_value decl with | Some _ -> aux (i+1) tel | None -> noccur_between (nenv - i) 1 t :: aux (i+1) tel in aux 0 (List.rev uparams) (** Check if the uniform parameters appear in a context *) let check_strpos_context env uparams default cxt = let rec aux env strpos tel = match tel with | [] -> (env, strpos) | decl::tel -> if Option.has_some @@ get_value decl then aux (push_rel decl env) strpos tel else let ty = whd_all env @@ get_type decl in let strpos_decl = check_strpos env uparams ty in aux (push_rel decl env) (List.map2 (&&) strpos_decl strpos) tel in aux env default (List.rev cxt) module Cache = struct type t = { mutable uniform : bool list Mindmap_env.t } let empty () = { uniform = Mindmap_env.empty } end (** Computes which uniform parameters are strictly positive in an argument *) let rec compute_params_rec_strpos_arg cache env kn uparams nparams_rec nparams init_value arg = (* strictly positive uniform parameters do not appear on the left of an arrow *) let (local_vars, hd) = Reduction.whd_decompose_prod_decls env arg in let (env, strpos_local) = check_strpos_context env uparams init_value local_vars in (* check the head *) let (hd, inst_args) = decompose_app hd in let srpos_hd = match kind hd with | Rel k -> (* Check if it is the inductive *) if List.length (Environ.rel_context env) < k then (* If it is the inductive, then they should not appear in the instantiation of the non-uniform parameters and indices of the inductive type being defined *) let (_, iargs) = Array.chop nparams_rec inst_args in andl_array (check_strpos env uparams) init_value iargs (* Otherwise, they should not appear in the arguments *) else andl_array (check_strpos env uparams) init_value inst_args | Ind ((kn_nested, _), _) -> (* Check if it is the inductive or nested *) if QMutInd.equal env kn kn_nested then (* If it is the inductive, then they should not appear in the instantiation of the non-uniform parameters and indices of the inductive type being defined *) let (_, iargs) = Array.chop nparams_rec inst_args in andl_array (check_strpos env uparams) init_value iargs (* For nested arguments, they should: *) else begin let mib_nested = lookup_mind kn_nested env in let mib_nested_strpos = compute_params_rec_strpos cache env kn_nested mib_nested in let (inst_uparams, inst_nuparams_indices) = Array.chop mib_nested.mind_nparams_rec inst_args in let uparams_nested = List.rev @@ fst @@ Context.Rel.chop_nhyps mib_nested.mind_nparams_rec @@ List.rev mib_nested.mind_params_ctxt in let inst_uparams = Termops.eta_expand_instantiation env inst_uparams uparams_nested in (* - appear strictly positively in the instantiation of the uniform parameters that are strictly postive themselves - not appear in uniform parameters that are not strictly postive *) let strpos_inst_uparams = Array.fold_right_i (fun i x acc -> if List.nth mib_nested_strpos i then List.map2 (&&) acc @@ compute_params_rec_strpos_arg cache env kn uparams nparams_rec nparams init_value x else List.map2 (&&) acc @@ check_strpos env uparams x ) inst_uparams init_value in (* - not appear in the instantiation of the non-uniform parameters and indices *) let strpos_inst_nuparams_indices = andl_array (check_strpos env uparams) init_value inst_nuparams_indices in List.map2 (&&) strpos_inst_uparams strpos_inst_nuparams_indices end | _ -> check_strpos env uparams hd in List.map2 (&&) strpos_local srpos_hd (** Computes which uniform parameters are strictly positive in a constructor *) and compute_params_rec_strpos_ctor cache env kn uparams nparams_rec nparams init_value (args, hd) = (* They must not appear on the left of an arrow in each argument *) let (env, strpos_args) = List.fold_right ( fun arg (env, acc) -> if Option.has_some @@ get_value arg then push_rel arg env, acc else let strpos_arg = compute_params_rec_strpos_arg cache env kn uparams nparams_rec nparams init_value (get_type arg) in (push_rel arg env, List.map2 (&&) acc strpos_arg) ) args (env, init_value) in (* They must not appear in the instantiation of the indices *) let (_, xs) = decompose_app hd in let inst_indices = Array.sub xs nparams (Array.length xs - nparams) in let str_inst_indices = andl_array (check_strpos env uparams) strpos_args inst_indices in let res_ctor = List.map2 (&&) strpos_args str_inst_indices in res_ctor (** Computes which uniform parameters are strictly positive in an inductive block *) and compute_params_rec_strpos_ind cache env kn uparams nparams_rec nparams init_value (indices, ctors) = (* They must not appear in indices *) let (_, strpos_indices) = check_strpos_context env uparams init_value indices in (* They must be strictly positive in each constructor *) let strpos_ctors = andl_array (compute_params_rec_strpos_ctor cache env kn uparams nparams_rec nparams init_value) init_value ctors in let res_ind = List.map2 (&&) strpos_indices strpos_ctors in res_ind (** Computes which uniform parameters are strictly positive in a mutual inductive block. [inds : (rel_context * (rel_declaration list * types) array) array] contains the context of indices, then for each constructor the telescope of arguments, and the hd. This function can be used whether the inductive is refered using [Rel] or [Ind]. This particular data representation is the one of indtypes. *) and compute_params_rec_strpos_aux cache env kn uparams nuparams nparams_rec nparams inds = if nparams_rec = 0 then [] else (* They must be arities [forall ..., sort X] *) let (env, init_value) = init_value env uparams in (* They must not appear in non-uniform parameters *) let (env, strpos_nuparams) = check_strpos_context env uparams init_value nuparams in (* They must be strictly positive in each inductive block *) let strpos_inds = andl_array (compute_params_rec_strpos_ind cache env kn uparams nparams_rec nparams init_value) init_value inds in let res = List.map2 (&&) strpos_nuparams strpos_inds in dbg_strpos Pp.(fun () -> MutInd.print kn ++ str ": Final Result = " ++ pp_strpos res); res and compute_params_rec_strpos cache env kn mib = match Mindmap_env.find_opt kn cache.Cache.uniform with | None -> (* reset the context *) let env = set_rel_context_val empty_rel_context_val env in (* compute the data expected *) let inds = Array.map (fun ind -> let (indices, _) = List.chop (List.length ind.mind_arity_ctxt - mib.mind_nparams) ind.mind_arity_ctxt in let ctors = Array.map (fun (args, hd) -> let (args,_) = List.chop (List.length args - mib.mind_nparams) args in (args, hd) ) ind.mind_nf_lc in (indices, ctors) ) mib.mind_packets in let (uparams, nuparams) = map_pair List.rev @@ Context.Rel.chop_nhyps mib.mind_nparams_rec @@ List.rev mib.mind_params_ctxt in let ans = compute_params_rec_strpos_aux cache env kn uparams nuparams mib.mind_nparams_rec mib.mind_nparams inds in let () = cache.Cache.uniform <- Mindmap_env.add kn ans cache.Cache.uniform in ans | Some unf -> unf (** {6 Lookup All Predicate and its Theorem } *) (** Suffix and register key for the [all] predicate and its theorem *) let default_suffix = (("_all", "_all_forall"), ("All", "AllForall")) let rec bool_list_to_string lb = match lb with | [] -> "" | true::l -> "1" ^ bool_list_to_string l | false::l -> "0" ^ bool_list_to_string l (** Suffix and register key for partial version of the [all] predicate and its theorem *) let partial_suffix strpos = let ((a, b), (c, d)) = default_suffix in let s = "_" ^ bool_list_to_string strpos in ((a^s, b^s), (c^s, d^s)) let rec compute_user_strpos_aux user_names allowed_uparams strpos = match user_names with | [] -> strpos | name::user_names -> let i = try CList.index0 (fun i n -> Name.equal i n) name allowed_uparams with | Not_found -> let allowed_uparams = List.filter Name.is_name allowed_uparams in CErrors.user_err Pp.( fmt "The variable %t is not included in the uniform parameters that are strictly positive and can be nested on" (fun () -> Name.print name) ++ if List.is_empty allowed_uparams then strbrk " because there are no such parameters." else fmt ".@ Allowed parameters are %t." (fun () -> pr_enum Name.print allowed_uparams) ) in dbg_strpos Pp.(fun () -> str "POSITION IS =" ++ int i); compute_user_strpos_aux user_names allowed_uparams (List.assign strpos i true) let compute_user_strpos mib user_id default_strpos = let user_names = List.map (fun i -> Name i) user_id in let uparams = fst @@ split_uparans_nuparams mib mib.mind_params_ctxt in let uparams_decl = List.filter is_local_assum uparams in let uparams_decl_name = List.map get_name uparams_decl in let allowed_uparams = List.map (fun (name, i) -> if i then name else Anonymous) @@ List.combine (List.rev uparams_decl_name) default_strpos in let strpos = List.map (fun _ -> false) uparams_decl in compute_user_strpos_aux user_names allowed_uparams strpos let compute_params_rec_strpos env kn mib = let cache = Cache.empty () in compute_params_rec_strpos cache env kn mib (** Compute the default positivity of the uniform parameters, and generates the suffix for naming the [all] predicate, and its theorem, as well as the key for registering. If a positivity specification is given by users [bool list option], it is checked to be included in the default one, and the suffix are modified accordingly. *) let compute_positive_uparams_and_suffix env kn mib user_id = let default_strpos = compute_params_rec_strpos env kn mib in match user_id with | None -> (default_strpos, fst default_suffix, snd default_suffix) | Some user_id -> let user_strpos = compute_user_strpos mib user_id default_strpos in let partial_suffix = partial_suffix user_strpos in (user_strpos, fst partial_suffix, snd partial_suffix) (** Warning for looking up the [all] predicate and its theorem *) let warn_lookup_not_found = CWarnings.create ~name:"register-all" ~category:CWarnings.CoreCategories.automation Pp.(fun (key, ind, ind_nested) -> Nametab.XRefs.pr (TrueGlobal (IndRef ind)) ++ strbrk " is nested using " ++ Nametab.XRefs.pr (TrueGlobal (IndRef ind_nested)) ++ strbrk ". " ++ strbrk "No scheme for " ++ Nametab.XRefs.pr (TrueGlobal (IndRef ind_nested)) ++ strbrk " is registered as " ++ strbrk key ++ strbrk ". " ++ strbrk "It can be generated using command \"Scheme All\" e.g. \"Scheme All for " ++ Nametab.XRefs.pr (TrueGlobal (IndRef ind_nested)) ++ str ".\"." ) (** Lookup the partial [all] predicate for [ind_nested] for [args_are_nested]. If they are not found, lookup the general [all] predicate. Returns if the partial [all] was found, and the global references. Raise a warning if none is found. *) let lookup_all ind ind_nested args_are_nested = let (_, (pred, _)) = partial_suffix args_are_nested in match DeclareScheme.lookup_scheme_opt pred ind_nested with | Some ref_pred -> Some (true, ref_pred) | None -> let (_, (pred, _)) = default_suffix in match DeclareScheme.lookup_scheme_opt pred ind_nested with | Some ref_pred -> Some (false, ref_pred) | None -> warn_lookup_not_found (pred, ind, ind_nested); None (** Lookup the [all] predicate, and its theorem *) let lookup_all_theorem_aux ind ind_nested = let (_, (pred, thm)) = default_suffix in match DeclareScheme.lookup_scheme_opt pred ind_nested with | None -> warn_lookup_not_found (pred, ind, ind_nested); None | Some ref_pred -> match DeclareScheme.lookup_scheme_opt thm ind_nested with | None -> warn_lookup_not_found (thm, ind, ind_nested); None | Some ref_thm -> Some (false, ref_pred, ref_thm) (** Lookup the partial [all] predicate and its theorem for [ind_nested] for [args_are_nested]. If they are not found, lookup the general [all] predicate and its theorem. Returns if the partial [all] was found, and the global references. Raise a warning if none is found. *) let lookup_all_theorem ind ind_nested args_are_nested = let (_, (pred, thm)) = partial_suffix args_are_nested in match DeclareScheme.lookup_scheme_opt pred ind_nested with | None -> lookup_all_theorem_aux ind ind_nested | Some ref_pred -> match DeclareScheme.lookup_scheme_opt thm ind_nested with | Some ref_thm -> Some (true, ref_pred, ref_thm) | None -> warn_lookup_not_found (thm, ind,ind_nested); lookup_all_theorem_aux ind ind_nested (** {6 Instantiate the All Predicate and its Theorem } *) open EConstr open Context open Inductive open LibBinding open State open Retyping open Rel.Declaration let (let@) x f = x f let (let*) x f = State.bind x f let dbg = CDebug.create ~name:"scheme-all" () let mkFunUnit x = let@ _ = rebind fid Lambda Fresh naming_id x in return @@ mkRef ((Rocqlib.lib_ref "core.unit.type"), EInstance.empty) let instantiate_all_uparams ~partial_nesting strpos inst_uparams inst_preds = let inst_preds = Array.to_list inst_preds in let inst_uparams = Array.to_list inst_uparams in let* s = get_state in let* sigma = get_sigma in let inst_sparam = List.fold_right (fun (positive, inst_uparam, pred) acc -> if not positive then inst_uparam :: acc else match pred with | Some pred -> inst_uparam :: pred :: acc | None -> if partial_nesting then inst_uparam :: acc else inst_uparam :: (snd @@ run_state s sigma @@ mkFunUnit inst_uparam) :: acc ) (List.combine3 strpos inst_uparams inst_preds) [] in return @@ Array.of_list inst_sparam (** Make the [all] predicate for a fresh instance and using [Typing.checked_appvect], given: - whether the [all] predicate is the partial one, or the general one [partial_nesting:bool] - the positivity of each uniform parameter [bool list] - the instantiation of the uniform parameter of the inductive type [constr array] - the instation of the fresh predicate [constr option array], using [fun ... => True] if the values are none, and [all] is the general predicate - the instantiation of the non-uniform parameters and indices - the argument to apply it to *) let make_all_predicate ~partial_nesting ref_all strpos inst_uparams inst_preds inst_nuparams_indices arg = let* ref_ind = fresh_global ref_all in let* inst_uparams = instantiate_all_uparams ~partial_nesting strpos inst_uparams inst_preds in typing_checked_appvect ref_ind @@ Array.concat [inst_uparams; inst_nuparams_indices; [|arg|]] let mkFuntt x = let@ _ = rebind fid Lambda Fresh naming_id x in return @@ mkRef ((Rocqlib.lib_ref "core.unit.tt"), EInstance.empty) let instantiate_all_theorem_uparams ~partial_nesting strpos inst_uparams preds preds_hold = let inst_uparams = Array.to_list inst_uparams in let preds = Array.to_list preds in let preds_hold = Array.to_list preds_hold in let* s = get_state in let* sigma = get_sigma in let inst_lfth = List.fold_right (fun (positive, inst_uparam, (pred, pred_hold)) acc -> if not positive then inst_uparam :: acc else match pred, pred_hold with | Some pred, Some pred_hold -> inst_uparam :: pred :: pred_hold :: acc | None, None -> if partial_nesting then inst_uparam :: acc else inst_uparam :: (snd @@ run_state s sigma @@ mkFunUnit inst_uparam) :: (snd @@ run_state s sigma @@ mkFuntt inst_uparam) :: acc | _, _ -> assert false ) (List.combine3 strpos inst_uparams @@ List.combine preds preds_hold) [] in return @@ Array.of_list inst_lfth (** Make the theorem for the [all] predicate for a fresh instance and using [Typing.checked_appvect], given: - whether the [all] predicate is the partial one, or the general one [partial_nesting:bool] - the positivity of each uniform parameter [bool list] - the instantiation of the uniform parameter of the inductive type [constr array] - the instation of the fresh predicate and the proofs they hold [constr option array], using [fun ... => True] and [fun _ => I] if the values are none, and [all] is the general predicate - the instantiation of the non-uniform parameters and indices - the argument to apply it to *) let make_all_theorem ~partial_nesting ref_all_thm strpos inst_uparams inst_preds inst_preds_hold inst_nuparams_indices arg = let* ref_ind = fresh_global ref_all_thm in let* inst_uparams = instantiate_all_theorem_uparams ~partial_nesting strpos inst_uparams inst_preds inst_preds_hold in typing_checked_appvect ref_ind @@ Array.concat [inst_uparams; inst_nuparams_indices; [|arg|]] (** {6 View for Arguments } *) type head_argument = | ArgIsSPUparam of int * constr array (** constant context, position of the uniform parameter, args *) | ArgIsInd of int * constr array * constr array (** constant context, position of the one_inductive body, inst_nuparams inst_indices *) | ArgIsNested of MutInd.t * int * mutual_inductive_body * bool list * one_inductive_body * constr array * constr array (** constant context, ind_nested, mutual and one body, strictly positivity of its uniform parameters, instantiation uniform paramerters, and of both non_uniform parameters and indices *) | ArgIsCst (** View to decompose arguments as [forall locs, X] where [X] is further decomposed as a uniform parameter, the inductive, ainstantiate_all nested argument or a constant. *) type argument = rel_context * head_argument (** Decompose the argument in [it_Prod_or_LetIn local, X] where [X] is a uniform parameter, Ind, nested or a constant *) let view_argument kn mib key_uparams strpos t = let* (cxt, hd) = whd_decompose_prod_decls t in let@ _ = add_context Old naming_id cxt in let* (hd, iargs) = decompose_app hd in let* sigma = get_sigma in match kind sigma hd with | Rel k -> begin (* Check if the debruijn variable corresponds to a strictly positive uniform parameter *) let* pos_up = check_key_in k key_uparams in match pos_up with | None -> return @@ (cxt, ArgIsCst) | Some i -> if List.nth strpos i then return @@ (cxt, ArgIsSPUparam (i, iargs)) else return @@ (cxt, ArgIsCst) end | Ind ((kn_ind, pos_ind), _) -> (* If it is the inductive *) if kn = kn_ind then let (_, local_nuparams_indices) = Array.chop mib.mind_nparams_rec iargs in let nb_nuparams = mib.mind_nparams - mib.mind_nparams_rec in let (local_nuparams, local_indices) = Array.chop nb_nuparams local_nuparams_indices in return @@ (cxt, ArgIsInd (pos_ind, local_nuparams, local_indices)) (* if there is no argument, it cannot be nested *) else if Array.length iargs = 0 then return @@ (cxt, ArgIsCst) else (* If it may be nested *) let* env = get_env in let (mib_nested, ind_nested) = lookup_mind_specif env (kn_ind, pos_ind) in let mib_nested_strpos = compute_params_rec_strpos env kn_ind mib_nested in (* Check if at least one parameter can be nested upon *) if List.exists (fun a -> a) mib_nested_strpos then let (inst_uparams, inst_nuparams_indices) = Array.chop mib_nested.mind_nparams_rec iargs in return @@ (cxt, ArgIsNested (kn_ind, pos_ind, mib_nested, mib_nested_strpos, ind_nested, inst_uparams, inst_nuparams_indices)) else return @@ (cxt, ArgIsCst) | _ -> return @@ (cxt, ArgIsCst) (** {6 Generate All Predicate } *) (* To build sparse parametricity: - For each positive uniform parameter [A : Type] add a predicate [PA : A -> Type] - For each argument [a : A] add [PA a], for each inductive a recursion hypothesis - Replace [tInd] by the corresponding [rel] *) (** {7 Functions on Parameters } *) let get_params_sep sigma mib u = let (sigma, params, sub_temp) = Inductiveops.paramdecls_fresh_template sigma (mib, u) in let (uparams, nuparams) = split_uparans_nuparams mib params in (sigma, uparams, nuparams, sub_temp) (** Closure of non-uniform parameters if [b], forgetting letins *) let closure_nuparams m binder naming_scheme nuparams = closure_context m binder Old naming_scheme nuparams let add_context_nuparams naming_scheme nuparams = add_context Old naming_scheme nuparams (** Closure for indices. They are considered as [Fresh] as they are not in the context of the arguments *) let closure_indices m binder freshness naming_scheme indb u f = let* i = get_indices indb u in closure_context m binder freshness naming_scheme i f (** {7 Create Fresh Sorts } *) (** Create a fresh quality and level for each positive uniform parameter *) let create_fresh_sorts_ql strpos = let nb_sorts = List.fold_right (fun a b -> a + b) (List.map Bool.to_int strpos) 0 in let init = List.make nb_sorts 0 in list_mapi (fun _ _ -> fresh_sort_ql ~sort_rigid:true UnivRigid) init (** Create a fresh sort for each positive uniform parameter *) let create_fresh_sorts strpos = let nb_sorts = List.fold_right (fun a b -> a + b) (List.map Bool.to_int strpos) 0 in let init = List.make nb_sorts 0 in list_mapi (fun _ _ -> let* (q,l) = fresh_sort_ql ~sort_rigid:true UnivRigid in return @@ ESorts.make @@ Sorts.qsort q l ) init (** {7 Compute the Return Sort} *) (* Compute if an inductive is nested including for positive parameters to be able to create a fresh universe to handle the constrains created due to the lack of algebraic universes. *) let rec is_nested_arg_nested kn mib key_uparams strpos arg : bool t = let* (locs, hd) = view_argument kn mib key_uparams strpos arg in let@ _ = add_context Old naming_id locs in match hd with | ArgIsNested (_, _, mib_nested, _, _, inst_uparams, _) -> let uparams_nested = of_rel_context @@ fst @@ split_uparans_nuparams mib_nested mib_nested.mind_params_ctxt in let* inst_uparams = eta_expand_instantiation inst_uparams uparams_nested in let is_nested_arg_nested arg = let* (loc, hd) = decompose_lambda_decls arg in let@ _ = add_context Old naming_hd loc in is_nested_arg_nested kn mib key_uparams strpos hd in let* inst_uparams = array_mapi (fun _ -> is_nested_arg_nested) inst_uparams in return @@ Array.exists (fun x -> x) inst_uparams | ArgIsSPUparam _ | ArgIsInd _ -> return true | _ -> return false let is_nested_arg kn mib key_uparams strpos arg = let* (locs, hd) = view_argument kn mib key_uparams strpos arg in let@ _ = add_context Old naming_id locs in match hd with | ArgIsNested (kn_nested, _, mib_nested, _, _, inst_uparams, _) -> let uparams_nested = of_rel_context @@ fst @@ split_uparans_nuparams mib_nested mib_nested.mind_params_ctxt in let* inst_uparams = eta_expand_instantiation inst_uparams uparams_nested in let is_nested_arg_nested arg = let* (loc, hd) = decompose_lambda_decls arg in let@ _ = add_context Old naming_hd loc in is_nested_arg_nested kn mib key_uparams strpos hd in let* inst_uparams = array_mapi (fun _ -> is_nested_arg_nested) inst_uparams in return @@ Array.exists (fun x -> x) inst_uparams | _ -> return false (** Compute if an inductive is nested including for positive uniform parameters *) let is_nested_ind kn mib ind uparams nuparams strpos : bool t = let@ key_uparams = add_context Old naming_id uparams in let@ _ = add_context Old naming_id nuparams in let* s = get_state in let* sigma = get_sigma in return @@ Array.exists (fun ctor -> snd @@ run_state s sigma @@ let* (args, _) = get_args mib EInstance.empty ctor in fold_left_state (fun a l -> a::l) args (fun _ arg cc -> let* arg_is_nested = is_nested_arg kn mib key_uparams strpos (get_type arg) in let@ key_arg = add_decl Old naming_id arg in let* b = cc key_arg in return (arg_is_nested || b) ) (fun _ -> return false) ) ind.mind_nf_lc (** Compute the return sort of the [all] predicate by adding to the sort of the original inductive type: - the level of the fresh sort of each fresh predicate, - if the inductive is nested including with a positive uniform parameter, add a new universe level [ualg] to accumulates constrains coming from the instantation of the [all] predicates for nested arguments. This is needed due to the lack of algebraic universes. *) let compute_one_return_sort mib ind is_nested u sub_temp fresh_sorts_ql = let open Sorts in (* Recover the sort of the original inductive type *) let* sigma = get_sigma in let u = EInstance.kind sigma u in let ind_sort = UVars.subst_instance_sort u ind.mind_sort in let ind_sort = match sub_temp, mib.mind_template with | Some sub_temp, Some temp -> Template.template_subst_sort sub_temp temp.template_concl | _, _ -> ind_sort in (* Sup of the original levels + a fresh universe if it is nested. Returns the new universe, if there is one, and the return sort *) let sort_if_nested is_nested make_sort u = let mkSort u = mkSort @@ ESorts.make @@ make_sort u in let fresh_sorts_levels = List.map snd fresh_sorts_ql in let new_u = List.fold_right Univ.Universe.sup fresh_sorts_levels u in if not is_nested then return (None, mkSort new_u) else let* l_alg = new_univ_level_variable UnivRigid in let u_alg = Univ.Universe.make l_alg in let u_return_sort = Univ.Universe.sup new_u u_alg in return (Some (mkSort u_alg), mkSort u_return_sort) in (* Compute the new sort, preserving impredicativity *) match ind_sort with | SProp -> return (None, mkSort @@ ESorts.make sprop) | Prop -> return (None, mkSort @@ ESorts.make prop) | Set -> sort_if_nested is_nested sort_of_univ Univ.Universe.type0 | Type u -> sort_if_nested is_nested sort_of_univ u | QSort (q,u) -> sort_if_nested is_nested (qsort q) u (** Compute the return sort of each [one_inductive_body], and a a fresh sort to handle algebraic constrains if the [one_inductive_body] is nested *) let compute_return_sort kn u sub_temp mib uparams nuparams strpos fresh_sorts_ql = array_mapi (fun pos_ind ind -> let* ind_is_nested = is_nested_ind kn mib ind uparams nuparams strpos in compute_one_return_sort mib ind ind_is_nested u sub_temp fresh_sorts_ql ) mib.mind_packets (** {7 Generate the Type of All } *) let rebind_applied_arity m naming_scheme key_arg cc = (* decompose the arity *) let* arg_ty = State.get_type key_arg in let* (locs, hd) = whd_decompose_prod_decls arg_ty in let@ key_locs = closure_context fid Prod Fresh naming_scheme locs in (* make args *) let* locs_tm = get_terms key_locs in let* arg_tm = get_term key_arg in let head = mkApp (arg_tm, locs_tm) in (* rebind the arity apply to the local variables*) let* sigma = get_sigma in let head_rev = ESorts.relevance_of_sort @@ destSort sigma hd in let head_name = make_annot Anonymous head_rev in let@ key_head = build_binder fid Prod Fresh naming_scheme @@ LocalAssum (head_name, head) in (* continuation *) cc (key_locs, key_head) (** Create a fresh predicate [PA : A -> Type] given a variable that is an arity *) let mkPred key_arg sort = let@ _ = rebind_applied_arity fid naming_hd key_arg in return sort (** Create the assumption that a predicate [PA : A -> Type] hold [forall a, PA a] given a variable that is an arity *) let mkPredHold key_arg key_pred = let@ (key_locs, key_head) = rebind_applied_arity fid naming_hd key_arg in (* Return PA x1 ... xn a *) let* locs = get_terms key_locs in let* head = get_term key_head in let* pred = get_term key_pred in return @@ mkApp (pred, Array.concat [locs; [|head|]]) (** Given the position of uniform parameter that is positive, return the position among the positive uniform parameters *) let pos_uparams_to_pos_spuparams j strpos = let rec aux i n l = match l with | [] -> assert false | x::_ when x && i = j -> n | x::l when x -> aux (i+1) (n+1) l | _ :: l -> aux (i+1) n l in aux 0 0 strpos (** Take the closure of the uniform parameters adding fresh predicates for strictly positive uniform parameters [PA : A -> Type], and that it holds [forall a, PA a] if [pred_hold = true] *) let closure_uparams_preds_hold_gen ~mk_pred_hold binder uparams strpos fresh_sorts cc = (* let open Sorts in *) let rec aux i key_uparams key_preds key_uparams_preds key_preds_hold tel cc = match tel with | [] -> cc (((List.rev key_uparams), (List.rev key_preds), (List.rev key_uparams_preds)), (List.rev key_preds_hold)) | decl :: tel -> let@ key_up = binder Old naming_id decl in if (Option.has_some @@ get_value decl) then aux i key_uparams key_preds key_uparams_preds key_preds_hold tel cc else if not (List.nth strpos i) then aux (i+1) (key_up::key_uparams) key_preds (key_up::key_uparams_preds) key_preds_hold tel cc else let pred_sort = List.nth fresh_sorts @@ pos_uparams_to_pos_spuparams i strpos in (* create (PA : A -> s) *) let pred_id = Name.map (fun id -> Id.of_string @@ "P" ^ Id.to_string id) (get_name decl) in let pred_name = make_annot pred_id ERelevance.relevant in let* pred_type = mkPred key_up (mkSort pred_sort) in let@ key_pred = binder Fresh naming_id @@ LocalAssum (pred_name, pred_type) in (* create (HPA : forall a, PA a) *) if not mk_pred_hold then aux (i+1) (key_up::key_uparams) (key_pred::key_preds) (key_pred::key_up::key_uparams_preds) [] tel cc else let pred_hold_id = Name.map (fun id -> Id.of_string @@ "HP" ^ Id.to_string id) (get_name decl) in let pred_hold_rev = ESorts.relevance_of_sort @@ pred_sort in let pred_hold_name = make_annot pred_hold_id pred_hold_rev in let* pred_hold_type = mkPredHold key_up key_pred in let@ key_pred_hold = binder Fresh naming_id @@ LocalAssum (pred_hold_name, pred_hold_type) in aux (i+1) (key_up::key_uparams) (key_pred::key_preds) (key_pred::key_up::key_uparams_preds) (key_pred_hold::key_preds_hold) tel cc in aux 0 [] [] [] [] (List.rev uparams) cc let closure_uparams_preds m binder uparams strpos fresh_sorts cc = closure_uparams_preds_hold_gen ~mk_pred_hold:false (build_binder m binder) uparams strpos fresh_sorts (fun (x,_) -> cc x) let context_uparams_preds uparams strpos fresh_sorts cc = closure_uparams_preds_hold_gen ~mk_pred_hold:false add_decl uparams strpos fresh_sorts (fun (x,_) -> cc x) (** {7 Generate the Type of the [all] predicate } *) (** Generate the type of the [all] predicate provided the parameters have already been quantified *) let gen_all_type_param kn pos_ind u mib key_uparams key_nuparams return_sort = (* Closure uparams and predicates, nuparams and indices *) let ind = mib.mind_packets.(pos_ind) in let@ key_indices = closure_indices fid Prod Fresh naming_hd ind u in (* Bind the inductive *) let* ind_rev = ind_relevance ind u in let ind_name = make_annot Anonymous ind_rev in let* ind_term = make_ind ((kn, pos_ind), u) key_uparams key_nuparams key_indices in let@ _ = make_binder fid Prod naming_hd_fresh ind_name ind_term in return return_sort (** Generate the type of the [all] predicate *) let gen_all_type kn pos_ind u mib uparams strpos fresh_sorts nuparams return_sort = let@ (key_uparams, _, _) = closure_uparams_preds fid Prod uparams strpos fresh_sorts in let@ key_nuparams = closure_nuparams fid Prod naming_id nuparams in gen_all_type_param kn pos_ind u mib key_uparams key_nuparams return_sort (** Add the [one_inductive_body] of the [all] predicate in the context *) let add_inductive kn u mib return_sorts uparams strpos fresh_sorts nuparams cc = let* cxt = array_map2i (fun pos_ind ind return_sort -> let* ind_rev = ind_relevance ind u in let* ind_type = gen_all_type kn pos_ind u mib uparams strpos fresh_sorts nuparams return_sort in return (LocalAssum (make_annot Anonymous ind_rev, ind_type)) ) mib.mind_packets return_sorts in add_context Fresh naming_id (List.rev @@ Array.to_list cxt) cc (** {7 Generate the Type of the New Constructors } *) (** Recursively compute the predicate, returns [None] if it is not nested *) let compute_pred to_compute f i x : (constr option) t = if to_compute then let* (locs, head) = decompose_lambda_decls x in let@ key_loc = closure_context fopt Lambda Fresh naming_id locs in (* create new variable *) let* head_sort = retyping_sort_of head in let arg_rev = relevance_of_sort head_sort in let arg_name = make_annot Anonymous arg_rev in (* let name_var = make_annot Anonymous ERelevance.relevant in *) let@ key_arg = make_binder fopt Lambda naming_id arg_name head in let* arg_type = State.get_type key_arg in (* compute rec call *) let* res = f key_arg arg_type in return @@ res else return None (** Recursively compute the predicate, returns [None] if it is not nested *) let compute_pred_eta to_compute f i x = let* res = compute_pred to_compute f i x in let* sigma = get_sigma in let res = Option.map (Reductionops.shrink_eta sigma) res in return res (** Internal type to be able to refer to inductive blocks either through variables or through [MutInd.t] *) type ('a, 'b) vars_or_kn = IndIsVars of 'a | IndIsKn of 'b (** Compute the new argument *) let rec make_rec_call_hyp kn pos_ind mib rep_inds ((key_uparams, key_preds, key_uparams_preds) as key_up) strpos ualg key_arg arg_type = (* Decompose the argument, rebind local variables and compute the argument *) let* (locs, head) = view_argument kn mib key_uparams strpos arg_type in let@ key_locals = closure_context fopt Prod Fresh naming_id locs in let* arg_term = get_term key_arg in let* locs_term = get_terms key_locals in let inst_arg = mkApp (arg_term, locs_term) in (* Match head *) match head with | ArgIsSPUparam (pos_uparam, iargs) -> let pos_in_keys = pos_uparams_to_pos_spuparams pos_uparam strpos in let* pred_tm = geti_term key_preds pos_in_keys in let pred = mkApp (pred_tm, Array.concat [ iargs; [|inst_arg|] ]) in return @@ Some pred | ArgIsInd (pos_ind_block, inst_nuparams, inst_indices) -> begin let* inst_uparams_preds = get_terms key_uparams_preds in let ind_args = Array.concat [inst_uparams_preds; inst_nuparams; inst_indices; [|inst_arg|]] in match rep_inds with | IndIsVars key_inds -> let* ind = geti_term key_inds pos_ind_block in return @@ Some (mkApp (ind, ind_args)) | IndIsKn (kn_all, u_all) -> return @@ Some (mkApp (mkIndU ((kn_all, pos_ind), u_all), ind_args)) end | ArgIsNested (kn_nested, pos_nested, mib_nested, mib_nested_strpos, ind_nested, inst_uparams, inst_nuparams_indices) -> (* eta expand arguments *) let uparams_nested = of_rel_context @@ fst @@ split_uparans_nuparams mib_nested mib_nested.mind_params_ctxt in let* inst_uparams = eta_expand_instantiation inst_uparams uparams_nested in (* Compute the recursive predicates *) let compute_pred i x b = compute_pred_eta b (make_rec_call_hyp kn pos_ind mib rep_inds key_up strpos ualg) i x in let* rec_preds = array_map2i compute_pred inst_uparams (Array.of_list mib_nested_strpos) in (* If at least one argument is nested, lookup the sparse parametricity *) let args_are_nested = Array.map Option.has_some rec_preds in if Array.for_all not args_are_nested then return None else begin match lookup_all (kn, pos_ind) (kn_nested, pos_nested) (Array.to_list args_are_nested) with | None -> return None | Some (partial_nesting, ref_pred) -> (* Create: all A0 PA0 ... An PAn B0 ... Bm i0 ... il (arg a0 ... an) *) let* rec_hyp = make_all_predicate ~partial_nesting ref_pred mib_nested_strpos inst_uparams rec_preds inst_nuparams_indices inst_arg in (* Add constrains with return sort *) match ualg with | None -> return (Some rec_hyp) | Some ualg -> let* jud = retyping_judgment_of rec_hyp in let* () = typing_check_actual_type jud ualg in return (Some rec_hyp) end | _ -> return None (** Create and bind the recursive call *) let make_rec_call_cc kn pos_ind mib key_inds ((key_uparams, key_preds, key_uparams_preds) as key_up) strpos ualg _ key_arg cc = let* arg_type = State.get_type key_arg in let* rec_call = make_rec_call_hyp kn pos_ind mib (IndIsVars key_inds) key_up strpos ualg key_arg arg_type in match rec_call with | None -> cc [key_arg] | Some rec_hyp -> (* Compute the relevance after the instantiation *) let* rec_hyp_sort = retyping_sort_of rec_hyp in let rec_hyp_rev = relevance_of_sort rec_hyp_sort in let rec_hyp_name = make_annot Anonymous rec_hyp_rev in let@ _ = make_binder fid Prod naming_id rec_hyp_name rec_hyp in cc [key_arg] (** Closure of the args, and of the rec call if [rec_hyp], and if any *) let closure_args_and_rec_call kn pos_ind mib key_inds key_up strpos ualg args = read_by_decl args (build_binder fid Prod Old naming_hd) (fun _ _ cc -> cc []) (make_rec_call_cc kn pos_ind mib key_inds key_up strpos ualg) (** Generate the type of the constructors of the [all] predicate supposing parameters have already been quantified: [ ∀ [args + rec], Indε (UP+PRED) NUP IND (cst up nup args) ] *) let gen_all_type_ctor kn pos_ind u mib key_inds ((key_uparams, key_preds, key_uparams_preds) as key_up) strpos key_nuparams ualg pos_ctor ctor = let* (args, indices) = get_args mib u ctor in let@ key_args = closure_args_and_rec_call kn pos_ind mib key_inds key_up strpos ualg args in (* Build the new inductive *) let* ind = geti_term key_inds pos_ind in let* inst_uparams_preds = get_terms key_uparams_preds in let* inst_nuparams = get_terms key_nuparams in let* inst_indices = array_mapi (fun _ -> weaken) indices in let ind = mkApp (ind, Array.concat [inst_uparams_preds; inst_nuparams; inst_indices]) in (* Builds the constructor *) let* cst_args = get_terms key_args in let* cst = make_cst ((kn, pos_ind), u) pos_ctor key_uparams key_nuparams cst_args in (* Return *) return @@ mkApp (ind, [|cst|]) (** {7 Make Entries } *) open Entries (** Generate the [one_inductive_entry] of the [all] predicate *) let gen_all_one_ind suffix kn pos_ind ind u mib return_sorts key_inds key_up strpos key_nuparams : one_inductive_entry t = let ulag, return_sort = return_sorts.(pos_ind) in let ind_id = add_suffix ind.mind_typename suffix in let* ind_type = gen_all_type_param kn pos_ind u mib ((fun (a,_,_) -> a) key_up) key_nuparams return_sort in let ctors_id = Array.map (fun x -> add_suffix x suffix) ind.mind_consnames in let* ctors_type = array_mapi (gen_all_type_ctor kn pos_ind u mib key_inds key_up strpos key_nuparams ulag) ind.mind_nf_lc in let* sigma = get_sigma in return { mind_entry_typename = ind_id ; mind_entry_arity = to_constr sigma ind_type ; mind_entry_consnames = Array.to_list ctors_id; mind_entry_lc = Array.to_list @@ Array.map (to_constr sigma) ctors_type; } let generate_all_aux suffix kn u sub_temp mib uparams strpos nuparams = (* create fresh sorts, and return types *) let* fresh_sorts_ql = create_fresh_sorts_ql strpos in let* return_sorts = compute_return_sort kn u sub_temp mib uparams nuparams strpos fresh_sorts_ql in let fresh_sorts = List.map (fun (a,b) -> ESorts.make @@ Sorts.qsort a b) fresh_sorts_ql in (*uparams + preds, nuparams and recover the context of parameters *) let@ key_inds = add_inductive kn u mib (Array.map snd return_sorts) uparams strpos fresh_sorts nuparams in let@ key_up = context_uparams_preds uparams strpos fresh_sorts in let@ key_nuparams = add_context_nuparams naming_id nuparams in let* current_context = get_context in let ctxt_params = fst @@ List.chop (List.length current_context - Array.length mib.mind_packets) current_context in (* create the inductive body *) let* ind_bodies = array_mapi (fun pos_ind ind -> gen_all_one_ind suffix kn pos_ind ind u mib return_sorts key_inds key_up strpos key_nuparams ) mib.mind_packets in (* universes *) let* sigma = get_sigma in let uctx = Evd.ustate sigma in dbg Pp.(fun () -> str "Before Simpl, Ustate.t = " ++ UState.pr (Evd.ustate sigma) ++ str "\n"); let uctx = UState.collapse_above_prop_sort_variables ~to_prop:true uctx in let uctx = UState.normalize_variables uctx in let uctx = UState.minimize uctx in dbg Pp.(fun () -> str "After Simpl, Ustate.t = " ++ UState.pr (Evd.ustate sigma) ++ str "\n"); let ind_bodies = Array.map (fun ind -> { ind with mind_entry_arity = UState.nf_universes uctx ind.mind_entry_arity; mind_entry_lc = List.map (UState.nf_universes uctx) ind.mind_entry_lc } ) ind_bodies in (* build mentry *) let mie = let uctx = UState.context uctx in let _qlen, ulen = UVars.UContext.size uctx in { mind_entry_record = None; mind_entry_finite = mib.mind_finite; mind_entry_params = EConstr.to_rel_context sigma ctxt_params ; mind_entry_inds = Array.to_list ind_bodies; mind_entry_universes = Polymorphic_ind_entry uctx; mind_entry_variance = Some (Array.make ulen None); mind_entry_private = mib.mind_private; } in (* DEBUG FUNCTIONS *) let* env = get_env in let sigma = Evd.set_universe_context sigma uctx in let () = dbg Pp.(fun () -> let params = EConstr.of_rel_context mie.mind_entry_params in let ind = List.hd @@ mie.mind_entry_inds in let ind_ty = EConstr.of_constr @@ ind.mind_entry_arity in let ctors_ty = List.map EConstr.of_constr ind.mind_entry_lc in let open Termops.Internal in str "Type Sparse Parametricity = " ++ (print_constr_env env sigma (it_mkProd_or_LetIn ind_ty params)) ++ fnl () ++ prlist_with_sep (fun () -> fnl ()) (fun ty_cst -> str "Type Constructor " ++ str " = " ++ print_constr_env env sigma (it_mkProd_or_LetIn ty_cst params) ++ fnl () ) ctors_ty ) in (* RETURN *) return (uctx, mie) let generate_all_predicate env sigma kn u mib strpos suffix = let (sigma, uparams, nuparams, sub_temp) = get_params_sep sigma mib u in dbg Pp.(fun () -> str "strpos = " ++ prlist_with_sep (fun () -> str ", ") bool strpos); let (sigma, (uctx, mie)) = run env sigma @@ generate_all_aux suffix kn u sub_temp mib uparams strpos nuparams in (uctx, mie) (** {6 Generate the Theorem for the All Predicate } *) let make_ind_typing (kn, pos_ind) u key_uparams key_nuparams key_indices = let tInd = mkIndU ((kn, pos_ind), u) in let* inst_ind = get_terms (key_uparams @ key_nuparams @ key_indices) in let* ind = typing_checked_appvect tInd inst_ind in return ind let make_ccl kn_nested pos_ind u_all key_uparams_preds key_nuparams key_indices key_VarMatch = make_ind_typing (kn_nested, pos_ind) u_all key_uparams_preds key_nuparams (key_indices @ [key_VarMatch]) let return_type kn kn_nested pos_ind u u_all mib key_uparams key_uparams_preds nuparams = let@ key_nuparams = closure_nuparams fid Prod naming_id nuparams in (* Closure uparams and predicates, nuparams and indices *) let ind = mib.mind_packets.(pos_ind) in let@ key_indices = closure_indices fid Prod Fresh naming_hd ind u in (* Bind the inductive *) let* ind_rev = ind_relevance ind u in let ind_name = make_annot Anonymous ind_rev in let* ind_term = make_ind ((kn, pos_ind), u) key_uparams key_nuparams key_indices in let@ key_VarMatch = make_binder fid Prod naming_hd_fresh ind_name ind_term in (* Return the sort of the inductive *) make_ccl kn_nested pos_ind u_all key_uparams_preds key_nuparams key_indices key_VarMatch let rec make_rec_call_proof kn knu pos_ind mib ((key_uparams, _, _) as key_up) key_preds_hold key_fixs strpos key_arg arg_type = (* Decompose the argument, rebind local variables and compute the argument *) let* (locs, head) = view_argument kn mib key_uparams strpos arg_type in let@ key_locals = closure_context fopt Lambda Fresh naming_id locs in let* arg_term = get_term key_arg in let* locs_term = get_terms key_locals in let inst_arg = mkApp (arg_term, locs_term) in (* match head *) match head with | ArgIsSPUparam (pos_uparam, iargs) -> let pos_in_keys = pos_uparams_to_pos_spuparams pos_uparam strpos in let* pred_hold_tm = geti_term key_preds_hold pos_in_keys in let rec_hyp_proof = mkApp (pred_hold_tm, Array.concat [ iargs; [|inst_arg|] ]) in return @@ Some rec_hyp_proof | ArgIsInd (pos_ind_block, inst_nuparams, inst_indices) -> (* Fi B0 ... Bm i0 ... il (x a0 ... an) *) let* fix = geti_term key_fixs pos_ind_block in return @@ Some (mkApp (fix, Array.concat [inst_nuparams; inst_indices; [|inst_arg|]])) | ArgIsNested (kn_nested, pos_nested, mib_nested, mib_nested_strpos, ind_nested, inst_uparams, inst_nuparams_indices) -> (* eta expand arguments *) let uparams_nested = of_rel_context @@ fst @@ split_uparans_nuparams mib_nested mib_nested.mind_params_ctxt in let* inst_uparams = eta_expand_instantiation inst_uparams uparams_nested in (* Compute the recursive predicates, and their proofs *) let compute_pred_preds i x b = compute_pred_eta b (make_rec_call_hyp kn pos_ind mib (IndIsKn knu) key_up strpos None) i x in let* rec_preds = array_map2i compute_pred_preds inst_uparams (Array.of_list mib_nested_strpos) in let compute_pred_holds i x b = compute_pred_eta b (make_rec_call_proof kn knu pos_ind mib key_up key_preds_hold key_fixs strpos) i x in let* rec_preds_hold = array_map2i compute_pred_holds inst_uparams (Array.of_list mib_nested_strpos) in (* If at least one argument is nested, lookup the local fundamental theorem *) let args_are_nested = Array.map Option.has_some rec_preds_hold in if Array.for_all not args_are_nested then return None else begin match lookup_all_theorem (kn, pos_ind) (kn_nested, pos_nested) (Array.to_list args_are_nested) with | None -> return None | Some (partial_nesting, _, ref_thm) -> let* rec_hyp_proof = make_all_theorem ~partial_nesting ref_thm mib_nested_strpos inst_uparams rec_preds rec_preds_hold inst_nuparams_indices inst_arg in return @@ Some rec_hyp_proof end | _ -> return None let compute_args_fix kn knu pos_ind mib key_up key_preds_hold key_fixs strpos key_args = CList.fold_right_i (fun pos_arg key_arg acc -> let* acc = acc in let* arg_term = get_term key_arg in let* arg_type = State.get_type key_arg in let* rec_call_proof = make_rec_call_proof kn knu pos_ind mib key_up key_preds_hold key_fixs strpos key_arg arg_type in match rec_call_proof with | Some rec_call_proof -> return @@ arg_term :: rec_call_proof :: acc | None -> return @@ arg_term :: acc ) 0 key_args (return []) let make_cst_typing ((kn, pos_ind), u) pos_ctor key_uparams key_nuparams args = let tCst = mkConstructU (((kn, pos_ind), 1+pos_ctor), u) in let* params = get_terms (key_uparams @ key_nuparams) in typing_checked_appvect tCst (Array.concat [params; args]) let generate_all_theorem_aux kn kn_nested focus u mib uparams strpos nuparams : constr t = (* 1. Create fresh sorts + new unfiform parameters *) let* fresh_sorts = create_fresh_sorts strpos in let@ ((key_uparams, key_preds, key_uparams_preds) as key_up, key_preds_hold) = closure_uparams_preds_hold_gen ~mk_pred_hold:true (build_binder fid Lambda) uparams strpos fresh_sorts in (* Evd.ustate 2. Fixpoint *) let* u_all = array_mapi (fun pos_ind _ -> fresh_inductive_instance (kn_nested, pos_ind)) mib.mind_packets in let relevance_ind ind = Vars.subst_instance_relevance u @@ relevance_of_sort @@ ESorts.make ind.mind_sort in let fix_name pos_ind ind = make_annot (Name (Id.of_string "F")) (relevance_ind ind) in let fix_type pos_ind ind = return_type kn kn_nested pos_ind u u_all.(pos_ind) mib key_uparams key_uparams_preds nuparams in let fix_rarg pos_ind ind = (mib.mind_nparams - mib.mind_nparams_rec) + ind.mind_nrealargs in let is_rec = Array.length mib.mind_packets > 1 || (Inductiveops.mis_is_recursive mib.mind_packets.(0)) in let@ (key_fixs, pos_ind, ind) = (* Doe not create a fix if it is not-recursive and only has one inductive body *) if is_rec then make_fix (Array.to_list mib.mind_packets) focus fix_rarg fix_name fix_type else fun cc -> cc ([], 0, mib.mind_packets.(0)) in (* 3. Closure Nuparams / Indices / Var *) let@ key_nuparams = closure_nuparams fid Lambda naming_id nuparams in let ind = mib.mind_packets.(pos_ind) in let@ key_indices = closure_indices fid Lambda Fresh naming_hd ind u in let* ind_rev = ind_relevance ind u in let ind_name = make_annot Anonymous ind_rev in let* ind_term = make_ind ((kn, pos_ind), u) key_uparams key_nuparams key_indices in let@ key_VarMatch = make_binder fid Lambda naming_hd_fresh ind_name ind_term in (* 4 Match to prove P ... x *) let case_pred = make_ccl kn_nested pos_ind u_all.(pos_ind) key_uparams_preds key_nuparams in let* inst_params = get_terms (key_uparams @ key_nuparams )in let* var_match = get_term key_VarMatch in let* inst_indices = get_terms key_indices in let case_rev = relevance_ind ind in let@ (key_args, _, _, pos_ctor) = make_case_or_projections naming_hd_fresh mib (kn, pos_ind) ind u key_uparams key_nuparams inst_params inst_indices case_pred case_rev var_match in (* 5 Body of the branch *) let* args = compute_args_fix kn (kn_nested, u_all.(pos_ind)) pos_ind mib key_up key_preds_hold key_fixs strpos key_args in make_cst_typing ((kn_nested, pos_ind), u_all.(pos_ind)) pos_ctor key_uparams_preds key_nuparams (Array.of_list args) let generate_all_theorem env sigma kn kn_nested focus u mib strpos = let (sigma, uparams, nuparams, _) = get_params_sep sigma mib u in dbg Pp.(fun () -> str "strpos = " ++ prlist_with_sep (fun () -> str ", ") bool strpos); let (sigma, tm) = run env sigma @@ generate_all_theorem_aux kn kn_nested focus u mib uparams strpos nuparams in dbg Pp.(fun () -> str "All Theorem = " ++ Termops.Internal.print_constr_env env sigma tm ++ fnl ()); dbg Pp.(fun () -> str "UState = " ++ UState.pr (Evd.ustate sigma) ++ fnl ()); (sigma, tm)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>