diff options
author | 2006-02-22 12:10:51 +0000 | |
---|---|---|
committer | 2006-02-22 12:10:51 +0000 | |
commit | 580ede7de1e39172c5ec5f2fee1c9e6ae059a36d (patch) | |
tree | 0a3113a0dc88c96938fed956aa093d2fb2e50437 /contrib/funind/new_arg_principle.ml | |
parent | 0a981a6ff2efa519d89318117fa220b9f77b665d (diff) |
Julien:
+ Induction principle for general recursion
+ Bug correction in structural principles
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@8076 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'contrib/funind/new_arg_principle.ml')
-rw-r--r-- | contrib/funind/new_arg_principle.ml | 940 |
1 files changed, 581 insertions, 359 deletions
diff --git a/contrib/funind/new_arg_principle.ml b/contrib/funind/new_arg_principle.ml index 56d0473d9..03eacea27 100644 --- a/contrib/funind/new_arg_principle.ml +++ b/contrib/funind/new_arg_principle.ml @@ -16,20 +16,14 @@ open Indfun_common (* let msgnl = Pp.msgnl *) -let observe_tac s tac g = - if Tacinterp.get_debug () <> Tactic_debug.DebugOff - then - let msgnl = Pp.msgnl in - begin - msgnl (Printer.pr_goal (sig_it g)); - try - let v = tclINFO tac g in msgnl (str s ++(str " ")++(str "finished")); v - with e -> - msgnl (str "observation "++ str s++str " raised an exception: "++Cerrors.explain_exn e); raise e - end +let observe_tac s tac g = + if Tacinterp.get_debug () <> Tactic_debug.DebugOff + then Recdef.do_observe_tac s tac g else tac g -let tclTRYD tac = + + +let tclTRYD tac = if !Options.debug || Tacinterp.get_debug () <> Tactic_debug.DebugOff then tclTRY tac else tac @@ -60,13 +54,13 @@ let test_var args arg_num = -let rewrite_until_var arg_num : tactic = +let rewrite_until_var arg_num : tactic = let constr_eq = (Coqlib.build_coq_eq_data ()).Coqlib.eq in - let replace_if_unify arg (pat,cl,id,lhs) : tactic = - fun g -> - try - let (evd,matched) = - Unification.w_unify_to_subterm + let replace_if_unify arg (pat,cl,id,lhs) : tactic = + fun g -> + try + let (evd,matched) = + Unification.w_unify_to_subterm (pf_env g) ~mod_delta:false (pat,arg) cl.Clenv.env in let cl' = {cl with Clenv.env = evd } in @@ -74,8 +68,8 @@ let rewrite_until_var arg_num : tactic = (Equality.replace matched c2) g with _ -> tclFAIL 0 (str "") g in - let rewrite_on_step equalities : tactic = - fun g -> + let rewrite_on_step equalities : tactic = + fun g -> match kind_of_term (pf_concl g) with | App(_,args) when (not (test_var args arg_num)) -> (* tclFIRST (List.map (fun a -> observe_tac (str "replace_if_unify") (replace_if_unify args.(arg_num) a)) equalities) g *) @@ -84,303 +78,174 @@ let rewrite_until_var arg_num : tactic = raise (Util.UserError("", (str "No more rewrite" ++ pr_lconstr_env (pf_env g) (pf_concl g)))) in - fun g -> - let equalities = - List.filter - ( - fun (_,_,id_t) -> + fun g -> + let equalities = + List.filter + ( + fun (_,_,id_t) -> match kind_of_term id_t with - | App(f,_) -> eq_constr f constr_eq - | _ -> false + | App(f,_) -> eq_constr f constr_eq + | _ -> false ) (pf_hyps g) in - let f (id,_,ctype) = + let f (id,_,ctype) = let c = mkVar id in let eqclause = Clenv.make_clenv_binding g (c,ctype) Rawterm.NoBindings in let clause_type = Clenv.clenv_type eqclause in - let f,args = decompose_app (clause_type) in + let f,args = decompose_app (clause_type) in let rec split_last_two = function | [c1;c2] -> (c1, c2) | x::y::z -> - split_last_two (y::z) - | _ -> - error ("The term provided is not an equivalence") + split_last_two (y::z) + | _ -> + error ("The term provided is not an equivalence") in let (c1,c2) = split_last_two args in - (c2,eqclause,id,c1) + (c2,eqclause,id,c1) in - let matching_hyps = List.map f equalities in - tclTRY (tclREPEAT (tclPROGRESS (rewrite_on_step matching_hyps))) g + let matching_hyps = List.map f equalities in + tclTRY (tclREPEAT (tclPROGRESS (rewrite_on_step matching_hyps))) g - -exception Toberemoved_with_rel of int*constr -exception Toberemoved - -let prov_pte_prefix = "_____PTE" - -let is_pte_type t = - isSort (snd (decompose_prod t)) - -let is_pte (_,_,t) = is_pte_type t - -let is_pte_id = - let pref_length = String.length prov_pte_prefix in - function id -> - String.sub (string_of_id id) 0 pref_length = prov_pte_prefix -let compute_new_princ_type_from_rel replace - (rel_as_kn:mutual_inductive) = - let is_dom c = - match kind_of_term c with - | Ind((u,_)) -> u = rel_as_kn - | Construct((u,_),_) -> u = rel_as_kn - | _ -> false - in - let get_fun_num c = - match kind_of_term c with - | Ind(_,num) -> num - | Construct((_,num),_) -> num - | _ -> assert false - in - let dummy_var = mkVar (id_of_string "________") in - let mk_replacement i args = - mkApp(replace.(i),Array.map pop (array_get_start args)) - in - let rec has_dummy_var t = - fold_constr - (fun b t -> b || (eq_constr t dummy_var) || (has_dummy_var t)) - false - t - in - let rec compute_new_princ_type env pre_princ : types*(constr list) = -(* let _tim1 = Sys.time() in *) - let (new_princ_type,_) as res = - match kind_of_term pre_princ with - | Rel n -> - begin - match Environ.lookup_rel n env with - | _,_,t when is_dom t -> raise Toberemoved - | _ -> pre_princ,[] - end - | Prod(x,t,b) -> - compute_new_princ_type_for_binder mkProd env x t b - | Lambda(x,t,b) -> - compute_new_princ_type_for_binder mkLambda env x t b - | Ind _ | Construct _ when is_dom pre_princ -> raise Toberemoved - | App(f,args) when is_dom f -> - let var_to_be_removed = destRel (array_last args) in - let num = get_fun_num f in - raise (Toberemoved_with_rel (var_to_be_removed,mk_replacement num args)) - | App(f,args) -> - let new_args,binders_to_remove = - Array.fold_right (compute_new_princ_type_with_acc env) - args - ([],[]) - in - let new_f,binders_to_remove_from_f = compute_new_princ_type env f in - mkApp(new_f,Array.of_list new_args), - list_union_eq eq_constr binders_to_remove_from_f binders_to_remove - | LetIn(x,v,t,b) -> - compute_new_princ_type_for_letin env x v t b - | _ -> pre_princ,[] - in -(* if Tacinterp.get_debug () <> Tactic_debug.DebugOff *) -(* then *) -(* msgnl (str "compute_new_princ_type for "++ *) -(* pr_lconstr_env env pre_princ ++ *) -(* str" is "++ *) -(* pr_lconstr_env env new_princ_type); *) - res - - and compute_new_princ_type_for_binder bind_fun env x t b = - begin - try - let new_t,binders_to_remove_from_t = compute_new_princ_type env t in - let new_x : name = get_name (ids_of_context env) x in - let new_env = Environ.push_rel (x,None,t) env in - let new_b,binders_to_remove_from_b = compute_new_princ_type new_env b in - if List.exists (eq_constr (mkRel 1)) binders_to_remove_from_b - then (pop new_b),filter_map (eq_constr (mkRel 1)) pop binders_to_remove_from_b - else - ( - bind_fun(new_x,new_t,new_b), - list_union_eq - eq_constr - binders_to_remove_from_t - (List.map pop binders_to_remove_from_b) - ) - - with - | Toberemoved -> -(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) - let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [dummy_var] 1 b) in - new_b, List.map pop binders_to_remove_from_b - | Toberemoved_with_rel (n,c) -> -(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) - let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [c] n b) in - new_b, list_add_set_eq eq_constr (mkRel n) (List.map pop binders_to_remove_from_b) - end - and compute_new_princ_type_for_letin env x v t b = - begin - try - let new_t,binders_to_remove_from_t = compute_new_princ_type env t in - let new_v,binders_to_remove_from_v = compute_new_princ_type env v in - let new_x : name = get_name (ids_of_context env) x in - let new_env = Environ.push_rel (x,Some v,t) env in - let new_b,binders_to_remove_from_b = compute_new_princ_type new_env b in - if List.exists (eq_constr (mkRel 1)) binders_to_remove_from_b - then (pop new_b),filter_map (eq_constr (mkRel 1)) pop binders_to_remove_from_b - else - ( - mkLetIn(new_x,new_v,new_t,new_b), - list_union_eq - eq_constr - (list_union_eq eq_constr binders_to_remove_from_t binders_to_remove_from_v) - (List.map pop binders_to_remove_from_b) - ) - - with - | Toberemoved -> -(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) - let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [dummy_var] 1 b) in - new_b, List.map pop binders_to_remove_from_b - | Toberemoved_with_rel (n,c) -> -(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) - let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [c] n b) in - new_b, list_add_set_eq eq_constr (mkRel n) (List.map pop binders_to_remove_from_b) - end - and compute_new_princ_type_with_acc env e (c_acc,to_remove_acc) = - let new_e,to_remove_from_e = compute_new_princ_type env e - in - new_e::c_acc,list_union_eq eq_constr to_remove_from_e to_remove_acc - in - compute_new_princ_type - - -let make_refl_eq type_of_t t = +let make_refl_eq type_of_t t = let refl_equal_term = Lazy.force refl_equal in mkApp(refl_equal_term,[|type_of_t;t|]) -let case_eq tac body term g = +let case_eq tac body term g = (* msgnl (str "case_eq on " ++ pr_lconstr_env (pf_env g) term); *) let type_of_term = pf_type_of g term in - let term_eq = - make_refl_eq type_of_term term - in + let term_eq = + make_refl_eq type_of_term term + in let ba_fun ba : tactic = - fun g -> - tclTHENSEQ + fun g -> + tclTHENSEQ [intro_patterns [](* ba.branchnames *); - fun g -> - let (_,_,new_term_value_eq) = pf_last_hyp g in - let new_term_value = - match kind_of_term new_term_value_eq with - | App(f,[| _;_;args2 |]) -> args2 - | _ -> - Pp.msgnl (pr_gls g ++ fnl () ++ str "last hyp is" ++ + fun g -> + let (_,_,new_term_value_eq) = pf_last_hyp g in + let new_term_value = + match kind_of_term new_term_value_eq with + | App(f,[| _;_;args2 |]) -> args2 + | _ -> + Pp.msgnl (pr_gls g ++ fnl () ++ str "last hyp is" ++ pr_lconstr_env (pf_env g) new_term_value_eq ); - assert false + assert false in - let fun_body = + let fun_body = mkLambda(Anonymous,type_of_term,replace_term term (mkRel 1) body) - in - let new_body = mkApp(fun_body,[| new_term_value |]) in + in + let new_body = mkApp(fun_body,[| new_term_value |]) in tac (pf_nf_betaiota g new_body) g ] g in ( - tclTHENSEQ + tclTHENSEQ [ - generalize [term_eq]; + h_generalize [term_eq]; pattern_option [[-1],term] None; case_then_using Genarg.IntroAnonymous (ba_fun) None ([],[]) term - ] + ] ) g -let my_reflexivity : tactic = - let test_eq = - lazy (eq_constr (Coqlib.build_coq_eq ())) +let my_reflexivity : tactic = + let test_eq = + lazy (eq_constr (Coqlib.build_coq_eq ())) in - let build_reflexivity = + let build_reflexivity = lazy (fun ty t -> mkApp((Coqlib.build_coq_eq_data ()).Coqlib.refl,[|ty;t|])) in - fun g -> + fun g -> begin - match kind_of_term (pf_concl g) with - | App(eq,[|ty;t1;t2|]) when (Lazy.force test_eq) eq -> - if not (Termops.occur_existential t1) + match kind_of_term (pf_concl g) with + | App(eq,[|ty;t1;t2|]) when (Lazy.force test_eq) eq -> + if not (Termops.occur_existential t1) then tclTHEN (h_change None (mkApp(eq,[|ty;t1;t1|])) onConcl ) (apply ((Lazy.force build_reflexivity) ty t1)) - else if not (Termops.occur_existential t2) + else if not (Termops.occur_existential t2) then tclTHEN (h_change None (mkApp(eq,[|ty;t2;t2|])) onConcl ) (apply ((Lazy.force build_reflexivity) ty t2)) else tclFAIL 0 (str "") | _ -> tclFAIL 0 (str "") end g -let exactify_proof rec_pos ptes_to_fix : tactic = - let not_as_constant = Coqlib.build_coq_not () in - let or_as_ind = Coqlib.build_coq_or () in - let eq_not = eq_constr not_as_constant in +let exactify_proof rec_pos ptes_to_fix : tactic = + let not_as_constant = Coqlib.build_coq_not () in + let or_as_ind = Coqlib.build_coq_or () in + let eq_not = eq_constr not_as_constant in let eq_or = eq_constr or_as_ind in - let tac_res tac: tactic = - fun g -> + let tac_res tac: tactic = + fun g -> match kind_of_term (pf_concl g) with | Prod _ -> tclTHEN intro tac g - | App(f,_) -> - if eq_not f + | App(f,_) -> + if eq_not f then tclTHEN (intro_force true) (tclABSTRACT None (Cctac.cc_tactic [])) (* Equality.discr_tac None *) g - else if eq_or f + else if eq_or f then - tclSOLVE + tclSOLVE [tclTHEN simplest_left tac; tclTHEN simplest_right tac ] g else begin - match rec_pos with - | Some rec_pos -> - begin - match kind_of_term f with - | Var id -> + match rec_pos with + | Some rec_pos -> + begin + match kind_of_term f with + | Var id -> begin try let fix_id = Idmap.find id ptes_to_fix in - let fix = mkVar (fix_id) in - tclTHEN - (rewrite_until_var rec_pos) - (Eauto.e_resolve_constr fix) - g - with Not_found -> -(* Pp.msgnl (str "No fix found for "++ *) -(* pr_lconstr_env (pf_env g) f); *) + let fix = mkVar (fix_id) in + tclTHEN + (rewrite_until_var rec_pos) + (Eauto.e_resolve_constr fix) + g + with Not_found -> + (* Pp.msgnl (str "No fix found for "++ *) + (* pr_lconstr_env (pf_env g) f); *) tclFAIL 0 (str "No such fix found") g end - | _ -> tclFAIL 0 (str "Not a variable : " - (* (string_of_pp (pr_lconstr_env (pf_env g) f)) *) - ) g + | _ -> + tclCOMPLETE + (Eauto. gen_eauto false (false,5) [] (Some [])) + (* (string_of_pp (pr_lconstr_env (pf_env g) f)) *) + g end - | None -> tclFAIL 0 (str "Not a good term") g + | None -> + tclCOMPLETE (Eauto. gen_eauto false (false,5) [] (Some [])) g + end | _ -> tclFAIL 0 (str "Not a good term") g - in - let rec exactify_proof g = + in + let rec exactify_proof g = tclFIRST [ tclSOLVE [my_reflexivity]; tclSOLVE [Eauto.e_assumption]; tclSOLVE [Tactics.reflexivity ]; - tac_res exactify_proof + tac_res exactify_proof; + tclCOMPLETE + ( + tclREPEAT + ( + tclPROGRESS + (tclTHEN + (rew_all LR) + (Eauto. gen_eauto false (false,5) [] (Some [])) + ) + ) + ) ] g in - observe_tac "exactify_proof with " exactify_proof + observe_tac "exactify_proof with " exactify_proof let reduce_fname fnames : tactic = @@ -395,13 +260,13 @@ let reduce_fname fnames : tactic = ) onConcl in - let refold : tactic = - reduce + let refold : tactic = + reduce (Rawterm.Fold (List.map mkConst fnames)) onConcl in - fun g -> + fun g -> (* if Tacinterp.get_debug () <> Tactic_debug.DebugOff *) (* then msgnl (str "reduce_fname"); *) tclTHENSEQ @@ -411,40 +276,40 @@ let reduce_fname fnames : tactic = ] g -let h_exact ?(with_rew_all=false) c :tactic = +let h_exact ?(with_rew_all=false) c :tactic = observe_tac "h_exact " (exact_check c ) -let finalize_proof rec_pos fixes (hyps:identifier list) = +let finalize_proof rec_pos fixes (hyps:identifier list) = if Tacinterp.get_debug () <> Tactic_debug.DebugOff then Pp.msgnl (str "rec hyps are : " ++ prlist_with_sep spc Ppconstr.pr_id hyps); - let exactify_proof = exactify_proof rec_pos fixes in + let exactify_proof = exactify_proof rec_pos fixes in - let exactify_proof_with_id id : tactic = - let do_exactify_proof_with_id = - fun g -> - let res = + let exactify_proof_with_id id : tactic = + let do_exactify_proof_with_id = + fun g -> + let res = tclTHEN (Eauto.e_resolve_constr (mkVar id)) (tclTRY exactify_proof) - in + in tclTHEN res ((h_exact (Coqlib.build_coq_I ()))) g - in - fun g -> observe_tac "exactify_proof_with_id" do_exactify_proof_with_id g + in + fun g -> observe_tac "exactify_proof_with_id" do_exactify_proof_with_id g in - let apply_one_hyp hyp acc = - tclORELSE + let apply_one_hyp hyp acc = + tclORELSE ( exactify_proof_with_id hyp) acc in - let apply_one_hyp_with_rewall hyp acc = - tclORELSE + let apply_one_hyp_with_rewall hyp acc = + tclORELSE (tclTHEN (rew_all RL) (exactify_proof_with_id hyp) @@ -452,19 +317,19 @@ let finalize_proof rec_pos fixes (hyps:identifier list) = acc in - let apply_hyps = - tclTRYD( - (List.fold_right - apply_one_hyp + let apply_hyps = + tclTRYD( + (List.fold_right + apply_one_hyp hyps - (List.fold_right - apply_one_hyp_with_rewall - hyps + (List.fold_right + apply_one_hyp_with_rewall + hyps (tclFAIL 0 (str "No rec hyps found ") ) ) )) in - let finalize_proof fnames t : tactic = + let finalize_proof fnames t : tactic = let change_tac tac g = match kind_of_term ( pf_concl g) with | App(p,args) -> @@ -482,12 +347,12 @@ let finalize_proof rec_pos fixes (hyps:identifier list) = end | _ -> assert false in - fun g -> + fun g -> (* if Tacinterp.get_debug () <> Tactic_debug.DebugOff *) (* then *) (* msgnl (str "finalize with body "++ Printer.pr_lconstr t ++ *) (* str " on goal "++ Printer.pr_goal (sig_it g)); *) - (change_tac apply_hyps) g + (change_tac apply_hyps) g in finalize_proof @@ -495,17 +360,18 @@ let do_prove_princ_for_struct (rec_pos:int option) (fnames:constant list) (ptes:identifier list) (fixes:identifier Idmap.t) (hyps: identifier list) (term:constr) : tactic = - let finalize_proof term = + let finalize_proof term = finalize_proof rec_pos fixes hyps fnames term in let rec do_prove_princ_for_struct do_finalize term g = (* if Tacinterp.get_debug () <> Tactic_debug.DebugOff *) (* then msgnl (str "Proving with body : " ++ pr_lconstr_env (pf_env g) term); *) - let tac = + let tac = fun g -> match kind_of_term term with | Case(_,_,t,_) -> - case_eq (do_prove_princ_for_struct do_finalize) term t g + observe_tac "case_eq" + (case_eq (do_prove_princ_for_struct do_finalize) term t) g | Lambda(n,t,b) -> begin match kind_of_term( pf_concl g) with @@ -517,7 +383,7 @@ let do_prove_princ_for_struct let new_term = pf_nf_betaiota g' (mkApp(term,[|mkVar id|])) in do_prove_princ_for_struct do_finalize new_term g' ) g - | _ -> + | _ -> do_finalize term g end | Cast(t,_,_) -> do_prove_princ_for_struct do_finalize t g @@ -529,9 +395,9 @@ let do_prove_princ_for_struct match kind_of_term f with | Var _ | Construct _ | Rel _ | Evar _ | Meta _ | Ind _ -> do_prove_princ_for_struct_args do_finalize f args g - | Const c when not (List.mem c fnames) -> + | Const c when not (List.mem c fnames) -> do_prove_princ_for_struct_args do_finalize f args g - | Const _ -> + | Const _ -> do_finalize term g | _ -> warning "Applied binders not yet implemented"; @@ -540,123 +406,127 @@ let do_prove_princ_for_struct | Fix _ | CoFix _ -> error ( "Anonymous local (co)fixpoints are not handled yet") | Prod _ -> assert false - | LetIn (Name id,v,t,b) -> + | LetIn (Name id,v,t,b) -> do_prove_princ_for_struct do_finalize (subst1 v b) g - | LetIn(Anonymous,_,_,b) -> + | LetIn(Anonymous,_,_,b) -> do_prove_princ_for_struct do_finalize (pop b) g - | _ -> + | _ -> errorlabstrm "" (str "in do_prove_princ_for_struct found : "(* ++ *) (* pr_lconstr_env (pf_env g) term *) ) in tac g - and do_prove_princ_for_struct_args do_finalize f_args' args :tactic = - fun g -> + and do_prove_princ_for_struct_args do_finalize f_args' args :tactic = + fun g -> (* if Tacinterp.get_debug () <> Tactic_debug.DebugOff *) (* then msgnl (str "do_prove_princ_for_struct_args with " ++ *) (* pr_lconstr_env (pf_env g) f_args' *) (* ); *) - let tac = - match args with - | [] -> + let tac = + match args with + | [] -> do_finalize f_args' - | arg::args -> - let do_finalize new_arg = - tclTRYD + | arg::args -> + let do_finalize new_arg = + tclTRYD (do_prove_princ_for_struct_args do_finalize - (mkApp(f_args',[|new_arg|])) + (mkApp(f_args',[|new_arg|])) args ) - in + in do_prove_princ_for_struct do_finalize arg - in + in tclTRYD(tac) g in - do_prove_princ_for_struct + do_prove_princ_for_struct (finalize_proof) term +let is_pte_type t = + isSort (snd (decompose_prod t)) + +let is_pte (_,_,t) = is_pte_type t -let prove_princ_for_struct fun_num f_names nparams : tactic = - let fnames_as_constr = Array.to_list (Array.map mkConst f_names) in - let fbody = - match (Global.lookup_constant f_names.(fun_num)).const_body with - | Some b -> - let body = force b in - Tacred.cbv_norm_flags - (Closure.RedFlags.mkflags [Closure.RedFlags.fZETA]) +let prove_princ_for_struct fun_num f_names nparams : tactic = + let fnames_as_constr = Array.to_list (Array.map mkConst f_names) in + let fbody = + match (Global.lookup_constant f_names.(fun_num)).const_body with + | Some b -> + let body = force b in + Tacred.cbv_norm_flags + (Closure.RedFlags.mkflags [Closure.RedFlags.fZETA]) (Global.env ()) (Evd.empty) body | None -> error ( "Cannot define a principle over an axiom ") in - let rec_arg_num,fbody = - match kind_of_term fbody with - | Fix((idxs,fix_num),(_,_,ca)) -> + let rec_arg_num,fbody = + match kind_of_term fbody with + | Fix((idxs,fix_num),(_,_,ca)) -> begin Some (idxs.(fix_num) - nparams),substl (List.rev fnames_as_constr) ca.(fix_num) end | b -> None,fbody in let f_real_args = nb_lam fbody - nparams in - let test_goal_for_hyps g = - let goal_nb_prod = nb_prod (pf_concl g) in - goal_nb_prod = f_real_args + let test_goal_for_hyps g = + let goal_nb_prod = nb_prod (pf_concl g) in + goal_nb_prod = f_real_args in - let test_goal_for_args g = - let goal_nb_prod = nb_prod (pf_concl g) in - goal_nb_prod < 1 + let test_goal_for_args g = + let goal_nb_prod = nb_prod (pf_concl g) in + goal_nb_prod < 1 in - let rec intro_params tac params n : tactic = - if n = 0 + let rec intro_params tac params n : tactic = + if n = 0 then tac params - else + else tclTHEN (intro) - (fun g -> - let (id,_,_) = pf_last_hyp g in + (fun g -> + let (id,_,_) = pf_last_hyp g in intro_params tac (id::params) (n-1) g ) in - let rec intro_pte tac ptes : tactic = - tclTHEN - intro - (fun g -> - let (id,_,_) as pte = pf_last_hyp g in - if is_pte pte + let rec intro_pte tac ptes : tactic = + tclTHEN + intro + (fun g -> + let (id,_,_) as pte = pf_last_hyp g in + if is_pte pte then intro_pte tac (id::ptes) g - else + else tclTHENSEQ - [ generalize [(mkVar id)]; + [ h_generalize [(mkVar id)]; clear [id]; tac ptes ] g ) in - let rec intro_hyps tac hyps : tactic = - fun g -> + let rec intro_hyps tac hyps : tactic = + fun g -> if test_goal_for_hyps g then tac hyps g - else - tclTHEN - intro - (fun g' -> + else + tclTHEN + intro + (fun g' -> let (id,_,_) = pf_last_hyp g' in intro_hyps tac (id::hyps) g' ) g in - let do_fix ptes tac : tactic = - match rec_arg_num with + let do_fix ptes tac : tactic = + match rec_arg_num with | None -> tac (Idmap.empty) | Some fix_arg_num -> - fun g -> - let this_fix_id = (fresh_id (pf_ids_of_hyps g) "fix___") in - let ptes_to_fix = - List.fold_left2 - (fun acc pte fix -> + fun g -> + let this_fix_id = (fresh_id (pf_ids_of_hyps g) "fix___") in + let ptes_to_fix = + List.fold_left2 + (fun acc pte fix -> Idmap.add pte fix acc ) Idmap.empty @@ -665,27 +535,27 @@ let prove_princ_for_struct fun_num f_names nparams : tactic = in tclTHEN (h_mutual_fix this_fix_id (fix_arg_num +1) []) - (tac ptes_to_fix) + (tac ptes_to_fix) g in - let rec intro_args tac args : tactic = - fun g -> - if test_goal_for_args g + let rec intro_args tac args : tactic = + fun g -> + if test_goal_for_args g then tac args g - else - tclTHEN - intro - (fun g' -> + else + tclTHEN + intro + (fun g' -> let (id,_,_) = pf_last_hyp g' in intro_args tac (id::args) g' ) g in - let intro_tacs tac : tactic = - fun g -> + let intro_tacs tac : tactic = + fun g -> (* msgnl (str "introducing params"); *) intro_params - (fun params -> + (fun params -> (* msgnl (str "introducing properties"); *) intro_pte (fun ptes -> @@ -697,7 +567,7 @@ let prove_princ_for_struct fun_num f_names nparams : tactic = (fun ptes_to_fix -> (* msgnl (str "introducing args"); *) intro_args - (fun args -> + (fun args -> (* tclTHEN *) (* (reduce_fname (Array.to_list f_names)) *) (tac params ptes ptes_to_fix hyps args)) @@ -712,32 +582,33 @@ let prove_princ_for_struct fun_num f_names nparams : tactic = nparams g in - let apply_fbody g params args = + let apply_fbody g params args = (* msgnl (str "applying fbody"); *) let args' = List.rev_map mkVar args in - let f_args = + let f_args = List.fold_left (fun acc p -> (mkVar p)::acc) args' params - in - let app_f = applist(subst1 (mkConst f_names.(fun_num)) fbody,f_args) in + in + let app_f = applist(subst1 (mkConst f_names.(fun_num)) fbody,f_args) in (* Pp.msgnl (pr_lconstr_env (pf_env g) app_f); *) pf_nf_betaiota g app_f in - let prepare_goal_tac tac : tactic = - intro_tacs - (fun params ptes ptes_to_fix hyps args g -> - let app_f = apply_fbody g params args in + let prepare_goal_tac tac : tactic = + intro_tacs + (fun params ptes ptes_to_fix hyps args g -> + let app_f = apply_fbody g params args in (* msgnl (str "proving"); *) - match rec_arg_num with - Some rec_arg_num -> - let actual_args = - List.fold_left (fun y x -> x::y) + match rec_arg_num with + Some rec_arg_num -> + let actual_args = + List.fold_left (fun y x -> x::y) (List.rev args) params in - let to_replace = applist(mkConst f_names.(fun_num),List.map mkVar actual_args) in + let to_replace = + applist(mkConst f_names.(fun_num),List.map mkVar actual_args) in tclTHENS - (Equality.replace + (Equality.replace to_replace app_f ) @@ -752,7 +623,7 @@ let prove_princ_for_struct fun_num f_names nparams : tactic = (* Tactics.reflexivity) *) ] g - | None -> + | None -> tclTHEN (reduce_fname (Array.to_list f_names)) (tac (Array.to_list f_names) ptes ptes_to_fix hyps app_f) @@ -761,9 +632,205 @@ let prove_princ_for_struct fun_num f_names nparams : tactic = (* tac (Array.to_list f_names) ptes ptes_to_fix hyps app_f g *) ) in - prepare_goal_tac (fun g -> do_prove_princ_for_struct rec_arg_num g) + prepare_goal_tac (fun g -> do_prove_princ_for_struct rec_arg_num g) + + + +(* let case_eq term : tactic = *) +(* fun g -> *) +(* let type_of_term = pf_type_of g term in *) +(* let eq_proof_term = *) +(* let refl_equal_term = Lazy.force refl_equal in *) +(* mkApp(refl_equal_term,[|type_of_t;t|]) *) +(* in *) +(* let ba_fun ba = *) +(* tclDO ba.nassums h_intro *) +(* in *) +(* tclTHENSEQ *) +(* [ *) +(* h_generalize [eq_proof_term]; *) +(* pattern_option [[-1],term] None; *) +(* case_then_using Genarg.IntroAnonymous ba_fun term None ([],[]) term *) +(* ] *) +(* g *) + + +(* let heq_id = id_of_string "Heq" *) + +(* let do_prove_princ_for_struct *) +(* predicates_ids ptes_to_fix branches_ids params_ids args_ids rec_arg_num = *) +(* let rec do_prove_princ_for_struct eqs_id term = *) +(* match kind_of_term term with *) +(* | Case(_,_,t,_) -> *) +(* tclTHEN *) +(* (case_eq t) *) +(* (fun g -> *) +(* let heq = fresh_id (pf_ids_of_hyps g) heq in *) +(* tclTHEN *) +(* (h_intro heq) *) +(* (fun g' -> *) +(* let new_t_value = *) +(* match kind_of_term (pf_type_of g' (mkVar heq)) with *) +(* | App(_,[|_;_;value|]) -> value *) +(* | _ -> anomaly "should have been an equality" *) +(* in *) +(* let type_of_t = pf_type_of g' t in *) +(* let term_as_fun = *) +(* mkLambda(Anonymous,type_of_t, *) +(* replace_term term (mkRel 1) term *) +(* ) *) +(* in *) +(* let new_term = *) +(* pf_nf_betaiota g' (mkApp(term_as_fun,new_t_value)) *) +(* in do_prove_princ_for_struct (heq::eqs_id) new_term g' *) +(* ) *) +(* ) *) +(* | Lambda(n,t,b) -> *) +(* begin *) +(* match kind_of_term( pf_concl g) with *) +(* | Prod _ -> *) +(* tclTHEN *) +(* intro *) +(* (fun g' -> *) +(* let (id,_,_) = pf_last_hyp g' in *) +(* let new_term = pf_nf_betaiota g' (mkApp(term,[|mkVar id|])) *) +(* in *) +(* do_prove_princ_for_struct do_finalize eqs_id new_term g' *) +(* ) *) +(* | _ -> *) +(* do_finalize eqs_id term *) +(* end *) +(* | Cast(t,_,_) -> do_prove_princ_for_struct do_finalize eqs_id t *) +(* | Fix _ | CoFix _ -> *) +(* error ( "Anonymous local (co)fixpoints are not handled yet") *) +(* | LetIn (Name id,v,t,b) -> *) +(* do_prove_princ_for_struct do_finalize (subst1 v b) g *) +(* | LetIn(Anonymous,_,_,b) -> *) +(* do_prove_princ_for_struct do_finalize (pop b) g *) +(* | Prod _ -> assert false *) +(* | *) +(* in *) +(* do_prove_princ_for_struct [] *) + + +(* let fresh_id_from_name avoid na = *) +(* match get_name avoid na with *) +(* | Name id -> id *) +(* | _ -> assert false *) + + +(* let fresh_ids (acces_fun: 'a -> name) (l: 'a list)(avoid : identifier list) = *) +(* let rev_ids,avoid = *) +(* List.fold_left *) +(* (fun (rev_ids,avoid) e -> *) +(* let old_name = acces_fun e in *) +(* let new_id = fresh_id_from_name avoid old_name in *) +(* new_id::rev_ids,new_id::avoid *) +(* ) *) +(* ([],avoid) *) +(* l *) +(* in *) +(* List.rev rev_ids,avoid *) + +(* let fst' (x,_,_) = x *) + +(* let prove_princ_for_struct fun_num f_names nparams : tactic = *) +(* fun g -> *) +(* let fnames_as_constr = Array.to_list (Array.map mkConst f_names) in *) +(* let fbody = *) +(* match (Global.lookup_constant f_names.(fun_num)).const_body with *) +(* | Some b -> *) +(* let body = force b in *) +(* Tacred.cbv_norm_flags *) +(* (Closure.RedFlags.mkflags [Closure.RedFlags.fZETA]) *) +(* (Global.env ()) *) +(* (Evd.empty) *) +(* body *) +(* | None -> error ( "Cannot define a principle over an axiom ") *) +(* in *) +(* let rec_arg_num,fbody = *) +(* match kind_of_term fbody with *) +(* | Fix((idxs,fix_num),(_,_,ca)) -> *) +(* begin Some (idxs.(fix_num) - nparams),substl (List.rev fnames_as_constr) ca.(fix_num) end *) +(* | b -> None,fbody *) +(* in *) +(* let goal_info = compute_elim_sig (mkRel 0,Rawterm.NoBindings) (pf_concl g) in *) +(* let params_ids,to_avoid = fresh_ids fst' goal_info.Tactics.params [] in *) +(* let predicates_ids,to_avoid = fresh_ids fst' goal_info.predicates to_avoid in *) +(* let branches_ids,to_avoid = fresh_ids fst' goal_info.branches to_avoid in *) +(* let first_intros : tactic = *) +(* tclMAP h_intro (params_ids@predicates_ids@branches_ids) *) +(* in *) +(* let fix_id,to_avoid,fix_tac = *) +(* match rec_arg_num with *) +(* | None -> None,to_avoid,first_intros *) +(* | Some fix_arg_num -> *) +(* let this_fix_id = (fresh_id to_avoid "fix___") in *) +(* Some this_fix_id,this_fix_id::to_avoid, *) +(* tclTHEN *) +(* first_intros *) +(* (h_mutual_fix this_fix_id (fix_arg_num +1) []) *) +(* in *) +(* let ptes_to_fix = *) +(* List.fold_left2 *) +(* (fun acc pte fix -> *) +(* Idmap.add pte fix acc *) +(* ) *) +(* Idmap.empty *) +(* predicates_ids *) +(* [fix_id] *) +(* in *) +(* let args_ids,to_avoid = fresh_ids fst' goal_info.args to_avoid in *) +(* let (tac_replace,term : tactic*constr) = *) +(* let eqs_rhs = *) +(* let fbody_with_funs = *) +(* substl (List.rev_map mkConst (Array.to_list f_names)) fbody *) +(* in *) +(* applist (fbody_with_funs, (List.map mkVar (params_ids@args_ids))) *) +(* in *) +(* match rec_arg_num with *) +(* | Some rec_arg_num -> *) +(* let eqs_lhs = *) +(* applist(mkConst f_names.(fun_num),List.map mkVar args_ids) *) +(* in *) +(* tclTHENS *) +(* (Equality.replace eqs_lhs eqs_rhs) *) +(* [ *) +(* tclIDTAC (\* The proof continue in this branche *\) *) +(* ; *) +(* (\* Not in this one *\) *) +(* let id = List.nth (List.rev args_ids) (rec_arg_num ) in *) +(* tclCOMPLETE *) +(* (tclTHENSEQ *) +(* [(h_simplest_case (mkVar id)); *) +(* Tactics.intros_reflexivity *) +(* ]) *) +(* ],eqs_rhs *) +(* | None -> *) +(* unfold_in_concl *) +(* (Array.to_list (Array.map (fun x -> [],EvalConstRef x) f_names)), *) +(* eqs_rhs *) +(* in *) +(* tclTHENSEQ *) +(* [ *) +(* fix_tac; *) +(* tclMAP h_intro args_ids; *) +(* tac_replace; *) +(* do_prove_princ_for_struct *) +(* predicates_ids *) +(* ptes_to_fix *) +(* branches_ids *) +(* params_ids *) +(* args_ids *) +(* rec_arg_num *) +(* term *) +(* ] *) + + + + @@ -771,6 +838,159 @@ let prove_princ_for_struct fun_num f_names nparams : tactic = + + + + + + + + + + + + + +exception Toberemoved_with_rel of int*constr +exception Toberemoved + +let prov_pte_prefix = "_____PTE" + + + +let is_pte_id = + let pref_length = String.length prov_pte_prefix in + function id -> + String.sub (string_of_id id) 0 pref_length = prov_pte_prefix + +let compute_new_princ_type_from_rel replace + (rel_as_kn:mutual_inductive) = + let is_dom c = + match kind_of_term c with + | Ind((u,_)) -> u = rel_as_kn + | Construct((u,_),_) -> u = rel_as_kn + | _ -> false + in + let get_fun_num c = + match kind_of_term c with + | Ind(_,num) -> num + | Construct((_,num),_) -> num + | _ -> assert false + in + let dummy_var = mkVar (id_of_string "________") in + let mk_replacement i args = + mkApp(replace.(i),Array.map pop (array_get_start args)) + in + let rec has_dummy_var t = + fold_constr + (fun b t -> b || (eq_constr t dummy_var) || (has_dummy_var t)) + false + t + in + let rec compute_new_princ_type env pre_princ : types*(constr list) = +(* let _tim1 = Sys.time() in *) + let (new_princ_type,_) as res = + match kind_of_term pre_princ with + | Rel n -> + begin + match Environ.lookup_rel n env with + | _,_,t when is_dom t -> raise Toberemoved + | _ -> pre_princ,[] + end + | Prod(x,t,b) -> + compute_new_princ_type_for_binder mkProd env x t b + | Lambda(x,t,b) -> + compute_new_princ_type_for_binder mkLambda env x t b + | Ind _ | Construct _ when is_dom pre_princ -> raise Toberemoved + | App(f,args) when is_dom f -> + let var_to_be_removed = destRel (array_last args) in + let num = get_fun_num f in + raise (Toberemoved_with_rel (var_to_be_removed,mk_replacement num args)) + | App(f,args) -> + let new_args,binders_to_remove = + Array.fold_right (compute_new_princ_type_with_acc env) + args + ([],[]) + in + let new_f,binders_to_remove_from_f = compute_new_princ_type env f in + mkApp(new_f,Array.of_list new_args), + list_union_eq eq_constr binders_to_remove_from_f binders_to_remove + | LetIn(x,v,t,b) -> + compute_new_princ_type_for_letin env x v t b + | _ -> pre_princ,[] + in +(* if Tacinterp.get_debug () <> Tactic_debug.DebugOff *) +(* then *) +(* msgnl (str "compute_new_princ_type for "++ *) +(* pr_lconstr_env env pre_princ ++ *) +(* str" is "++ *) +(* pr_lconstr_env env new_princ_type); *) + res + + and compute_new_princ_type_for_binder bind_fun env x t b = + begin + try + let new_t,binders_to_remove_from_t = compute_new_princ_type env t in + let new_x : name = get_name (ids_of_context env) x in + let new_env = Environ.push_rel (x,None,t) env in + let new_b,binders_to_remove_from_b = compute_new_princ_type new_env b in + if List.exists (eq_constr (mkRel 1)) binders_to_remove_from_b + then (pop new_b),filter_map (eq_constr (mkRel 1)) pop binders_to_remove_from_b + else + ( + bind_fun(new_x,new_t,new_b), + list_union_eq + eq_constr + binders_to_remove_from_t + (List.map pop binders_to_remove_from_b) + ) + + with + | Toberemoved -> +(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) + let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [dummy_var] 1 b) in + new_b, List.map pop binders_to_remove_from_b + | Toberemoved_with_rel (n,c) -> +(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) + let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [c] n b) in + new_b, list_add_set_eq eq_constr (mkRel n) (List.map pop binders_to_remove_from_b) + end + and compute_new_princ_type_for_letin env x v t b = + begin + try + let new_t,binders_to_remove_from_t = compute_new_princ_type env t in + let new_v,binders_to_remove_from_v = compute_new_princ_type env v in + let new_x : name = get_name (ids_of_context env) x in + let new_env = Environ.push_rel (x,Some v,t) env in + let new_b,binders_to_remove_from_b = compute_new_princ_type new_env b in + if List.exists (eq_constr (mkRel 1)) binders_to_remove_from_b + then (pop new_b),filter_map (eq_constr (mkRel 1)) pop binders_to_remove_from_b + else + ( + mkLetIn(new_x,new_v,new_t,new_b), + list_union_eq + eq_constr + (list_union_eq eq_constr binders_to_remove_from_t binders_to_remove_from_v) + (List.map pop binders_to_remove_from_b) + ) + + with + | Toberemoved -> +(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) + let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [dummy_var] 1 b) in + new_b, List.map pop binders_to_remove_from_b + | Toberemoved_with_rel (n,c) -> +(* msgnl (str "Decl of "++Ppconstr.pr_name x ++ str " is removed "); *) + let new_b,binders_to_remove_from_b = compute_new_princ_type env (substnl [c] n b) in + new_b, list_add_set_eq eq_constr (mkRel n) (List.map pop binders_to_remove_from_b) + end + and compute_new_princ_type_with_acc env e (c_acc,to_remove_acc) = + let new_e,to_remove_from_e = compute_new_princ_type env e + in + new_e::c_acc,list_union_eq eq_constr to_remove_from_e to_remove_acc + in + compute_new_princ_type + let change_property_sort nparam toSort princ princName = let params,concl = decompose_prod_n nparam princ in let hyps,_ = decompose_prod concl in @@ -802,6 +1022,8 @@ let change_property_sort nparam toSort princ princName = in res +let prov_pte_prefix = "_____PTE" + let generate_new_structural_principle interactive_proof old_princ new_princ_name funs i proof_tac |