123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156(************************************************************************)(* * The Coq Proof Assistant / The Coq 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) *)(************************************************************************)openPpopenUtilopenCErrorsopenNamesopenSortsopenConstropenEConstropenTacmachopenTacticalsopenTacticsopenIndfun_commonmoduleRelDecl=Context.Rel.Declarationletis_rec_infosigmascheme_info=lettest_brancheminaccdecl=acc||letnew_branche=it_mkProd_or_LetInmkProp(fst(decompose_prod_assumsigma(RelDecl.get_typedecl)))inletfree_rels_in_br=Termops.free_relssigmanew_brancheinletmax=min+scheme_info.Tactics.npredicatesinInt.Set.exists(funi->i>=min&&i<max)free_rels_in_brinList.fold_left_itest_branche1false(List.revscheme_info.Tactics.branches)letchoose_dest_or_indscheme_infoargs=Proofview.tclBINDProofview.tclEVARMAP(funsigma->Tactics.induction_destruct(is_rec_infosigmascheme_info)falseargs)letfunctional_inductionwith_cleancprinclpat=letopenProofview.NotationsinProofview.Goal.enter_one(fungl->letsigma=projectglinletf,args=decompose_appsigmacinmatchprinclwith|None->((* No principle is given let's find the good one *)matchEConstr.kindsigmafwith|Const(c',u)->letprinc_option=letfinfo=(* we first try to find out a graph on f *)matchfind_Function_infosc'with|Somefinfo->finfo|None->user_err(str"Cannot find induction information on "++Printer.pr_leconstr_env(pf_envgl)sigma(mkConstc'))inmatchelimination_sort_of_goalglwith|InSProp->finfo.sprop_lemma|InProp->finfo.prop_lemma|InSet->finfo.rec_lemma|InType->finfo.rect_lemmainletsigma,princ=(* then we get the principle *)matchprinc_optionwith|Someprinc->Evd.fresh_global(pf_envgl)(projectgl)(GlobRef.ConstRefprinc)|None->(*i If there is not default lemma defined then,
we cross our finger and try to find a lemma named f_ind
(or f_rec, f_rect) i*)letprinc_name=Indrec.make_elimination_ident(Label.to_id(Constant.labelc'))(elimination_sort_of_goalgl)inletprinc_ref=matchConstrintern.locate_reference(Libnames.qualid_of_identprinc_name)with|Somer->r|None->user_err(str"Cannot find induction principle for "++Printer.pr_leconstr_env(pf_envgl)sigma(mkConstc'))inEvd.fresh_global(pf_envgl)(projectgl)princ_refinletprinct=Retyping.get_type_of(pf_envgl)sigmaprincinProofview.Unsafe.tclEVARSsigma<*>Proofview.tclUNIT(princ,Tactypes.NoBindings,princt,args)|_->CErrors.user_err(str"functional induction must be used with a function"))|Some(princ,binding)->letsigma,princt=pf_type_ofglprincinProofview.Unsafe.tclEVARSsigma<*>Proofview.tclUNIT(princ,binding,princt,args))>>=fun(princ,bindings,princ_type,args)->Proofview.Goal.enter(fungl->letsigma=projectglinletprinc_infos=compute_elim_sig(projectgl)princ_typeinletargs_as_induction_constr=letc_list=ifprinc_infos.Tactics.farg_in_conclthen[c]else[]inifList.lengthargs+List.lengthc_list=0thenuser_errPp.(str"Cannot recognize a valid functional scheme");letencoded_pat_as_patlist=List.make(List.lengthargs+List.lengthc_list-1)None@[pat]inList.map2(funcpat->((None,ElimOnConstr(funenvsigma->(sigma,(c,Tactypes.NoBindings)))),(None,pat),None))(args@c_list)encoded_pat_as_patlistinletprinc'=Some(princ,bindings)inletprinc_vars=List.fold_right(funaacc->tryId.Set.add(destVarsigmaa)accwithDestKO->acc)argsId.Set.emptyinletold_idl=List.fold_rightId.Set.add(pf_ids_of_hypsgl)Id.Set.emptyinletold_idl=Id.Set.diffold_idlprinc_varsinletsubst_and_reducegl=ifwith_cleanthenletidl=List.filter(funid->not(Id.Set.memidold_idl))(pf_ids_of_hypsgl)inletflag=Genredexpr.Cbv{Redops.all_flagswithGenredexpr.rDelta=false}intclTHEN(tclMAP(funid->tclTRY(Equality.subst_gen(do_rewrite_dependent())[id]))idl)(reduceflagLocusops.allHypsAndConcl)elsetclIDTACintclTHEN(choose_dest_or_indprinc_infos(args_as_induction_constr,princ'))(Proofview.Goal.entersubst_and_reduce))