123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562(************************************************************************)(* * 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) *)(************************************************************************)(* Created by Hugo Herbelin from contents related to inductive schemes
initially developed by Christine Paulin (induction schemes), Vincent
Siles (decidable equality and boolean equality) and Matthieu Sozeau
(combined scheme) in file command.ml, Sep 2009 *)(* This file provides entry points for manually or automatically
declaring new schemes *)openPpopenUtilopenDeclarationsopenTermopenGoptionsopenVernacexpropenInd_tablesopenAuto_ind_declopenEqschemesopenElimschemes(** Data of an inductive scheme with name resolved *)typeresolved_scheme=Names.Id.tCAst.t*Indrec.dep_flag*Names.inductive*Sorts.family(** flag for internal message display *)typeinternal_flag=|UserAutomaticRequest(* kernel action, a message is displayed *)|UserIndividualRequest(* user action, a message is displayed *)(* Flags governing automatic synthesis of schemes *)letelim_flag=reftruelet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Elimination";"Schemes"];optread=(fun()->!elim_flag);optwrite=(funb->elim_flag:=b)}letbifinite_elim_flag=reffalselet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Nonrecursive";"Elimination";"Schemes"];optread=(fun()->!bifinite_elim_flag);optwrite=(funb->bifinite_elim_flag:=b)}letcase_flag=reffalselet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Case";"Analysis";"Schemes"];optread=(fun()->!case_flag);optwrite=(funb->case_flag:=b)}leteq_flag=reffalselet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Boolean";"Equality";"Schemes"];optread=(fun()->!eq_flag);optwrite=(funb->eq_flag:=b)}letis_eq_flag()=!eq_flagleteq_dec_flag=reffalselet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Decidable";"Equality";"Schemes"];optread=(fun()->!eq_dec_flag);optwrite=(funb->eq_dec_flag:=b)}letrewriting_flag=reffalselet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Rewriting";"Schemes"];optread=(fun()->!rewriting_flag);optwrite=(funb->rewriting_flag:=b)}(* Util *)letdefine~polynamesigmactypes=letunivs=Evd.univ_entry~polysigmainletentry=Declare.definition_entry~univs?typescinletkind=Decls.(IsDefinitionScheme)inletkn=Declare.declare_constant~kind~name(Declare.DefinitionEntryentry)inDeclare.definition_messagename;kn(* Boolean equality *)letdeclare_beq_scheme_gen?locmapnameskn=ignore(define_mutual_scheme?locmapbeq_scheme_kindnameskn)letdebug=CDebug.create~name:"indschemes"()letalarmwhatinternalmsg=matchinternalwith|UserAutomaticRequest->debugPp.(fun()->hov0msg++fnl()++what++str" not defined.");None|UserIndividualRequest->Somemsglettry_declare_scheme?locmapwhatfinternalnameskn=tryf?locmapnamesknwithe->lete=Exninfo.captureeinletrecextract_exn=functionLogic_monad.TacticFailuree->extract_exne|e->einletmsg=matchextract_exn(fste)with|ParameterWithoutEqualitycst->alarmwhatinternal(str"Boolean equality not found for parameter "++Printer.pr_globalcst++str".")|InductiveWithProduct->alarmwhatinternal(str"Unable to decide equality of functional arguments.")|InductiveWithSort->alarmwhatinternal(str"Unable to decide equality of type arguments.")|NonSingletonPropind->alarmwhatinternal(str"Cannot extract computational content from proposition "++quote(Printer.pr_inductive(Global.env())ind)++str".")|EqNotFoundind'->alarmwhatinternal(str"Boolean equality on "++quote(Printer.pr_inductive(Global.env())ind')++strbrk" is missing.")|UndefinedCsts->alarmwhatinternal(strbrk"Required constant "++strs++str" undefined.")|DeclareUniv.AlreadyDeclared(kind,id)asexn->letmsg=CErrors.printexninalarmwhatinternalmsg|DecidabilityMutualNotSupported->alarmwhatinternal(str"Decidability lemma for mutual inductive types not supported.")|EqUnknowns->alarmwhatinternal(str"Found unsupported "++strs++str" while building Boolean equality.")|NoDecidabilityCoInductive->alarmwhatinternal(str"Scheme Equality is only for inductive types.")|DecidabilityIndicesNotSupported->alarmwhatinternal(str"Inductive types with indices not supported.")|ConstructorWithNonParametricInductiveTypeind->alarmwhatinternal(strbrk"Unsupported constructor with an argument whose type is a non-parametric inductive type."++strbrk" Type "++quote(Printer.pr_inductive(Global.env())ind)++str" is applied to an argument which is not a variable.")|InternalDependencies->alarmwhatinternal(strbrk"Inductive types with internal dependencies in constructors not supported.")|ewhenCErrors.noncriticale->alarmwhatinternal(str"Unexpected error during scheme creation: "++CErrors.printe)|_->Exninfo.iraiseeinmatchmsgwith|None->()|Somemsg->Exninfo.iraise(CErrors.UserErrormsg,snde)letbeq_scheme_msgmind=letmib=Global.lookup_mindmindin(* TODO: mutual inductive case *)str"Boolean equality on "++pr_enum(funind->quote(Printer.pr_inductive(Global.env())ind))(List.init(Array.lengthmib.mind_packets)(funi->(mind,i)))letdeclare_beq_scheme_with?locmaplkn=try_declare_scheme(beq_scheme_msgkn)declare_beq_scheme_genUserIndividualRequestlknlettry_declare_beq_scheme?locmapkn=(* TODO: handle Fix, eventually handle
proof-irrelevance; improve decidability by depending on decidability
for the parameters rather than on the bl and lb properties *)try_declare_scheme(beq_scheme_msgkn)declare_beq_scheme_genUserAutomaticRequest[]knletdeclare_beq_scheme?locmapmi=declare_beq_scheme_with?locmap[]mi(* Case analysis schemes *)letdeclare_one_case_analysis_scheme?locind=let(mib,mip)asspecif=Global.lookup_inductiveindinletkind=Indrec.pseudo_sort_family_for_elimindmipinletdep,suff=ifkind==InPropthencase_nodep,Some"case"elseifnot(Inductiveops.has_dependent_elimspecif)thencase_nodep,Noneelsecase_dep,Some"case"inletid=matchsuffwith|None->None|Somesuff->(* the auto generated eliminator may be called "case" instead of eg "case_nodep" *)SomeNames.(Id.of_string(Id.to_stringmip.mind_typename^"_"^suff))inletkelim=Inductiveops.elim_sort(mib,mip)in(* in case the inductive has a type elimination, generates only one
induction scheme, the other ones share the same code with the
appropriate type *)ifSorts.family_leqInTypekelimthendefine_individual_scheme?locdepidind(* Induction/recursion schemes *)letdeclare_one_induction_scheme?locind=let(mib,mip)asspecif=Global.lookup_inductiveindinletkind=Indrec.pseudo_sort_family_for_elimindmipinletfrom_prop=kind==InPropinletdepelim=Inductiveops.has_dependent_elimspecifinletkelim=Inductiveops.sorts_below(Inductiveops.elim_sort(mib,mip))inletkelim=ifGlobal.sprop_allowed()thenkelimelseList.filter(funs->s<>InSProp)keliminletelims=List.filter(fun(sort,_)->List.mem_fSorts.family_equalsortkelim)(* NB: the order is important, it makes it so that _rec is
defined using _rect but _ind is not. *)[(InType,"rect");(InProp,"ind");(InSet,"rec");(InSProp,"sind")]inletelims=List.map(fun(to_kind,dflt_suff)->iffrom_propthenelim_scheme~dep:false~to_kind,Somedflt_suffelseifdepelimthenelim_scheme~dep:true~to_kind,Somedflt_suffelseelim_scheme~dep:false~to_kind,None)elimsinList.iter(fun(kind,suff)->letid=matchsuffwith|None->None|Somesuff->(* the auto generated eliminator may be called "rect" instead of eg "rect_dep" *)SomeNames.(Id.of_string(Id.to_stringmip.mind_typename^"_"^suff))indefine_individual_scheme?lockindidind)elimsletdeclare_induction_schemes?(locmap=Locmap.defaultNone)kn=letmib=Global.lookup_mindkninifmib.mind_finite<>Declarations.CoFinitethenbeginfori=0toArray.lengthmib.mind_packets-1doletloc=Ind_tables.Locmap.lookup~locmap(kn,i)indeclare_one_induction_scheme(kn,i)?loc;done;end(* Decidable equality *)letdeclare_eq_decidability_gen?locmapnameskn=letmib=Global.lookup_mindkninifmib.mind_finite<>Declarations.CoFinitethendefine_mutual_scheme?locmapeq_dec_scheme_kindnamesknleteq_dec_scheme_msgind=(* TODO: mutual inductive case *)str"Decidable equality on "++quote(Printer.pr_inductive(Global.env())ind)letdeclare_eq_decidability_scheme_with?locmaplkn=try_declare_scheme?locmap(eq_dec_scheme_msg(kn,0))declare_eq_decidability_genUserIndividualRequestlknlettry_declare_eq_decidability?locmapkn=try_declare_scheme?locmap(eq_dec_scheme_msg(kn,0))declare_eq_decidability_genUserAutomaticRequest[]knletdeclare_eq_decidability?locmapmi=declare_eq_decidability_scheme_with?locmap[]miletignore_errorfx=tryfxwithewhenCErrors.noncriticale->()letdeclare_rewriting_schemes?locind=ifHipattern.is_inductive_equality(Global.env())indthenbegindefine_individual_scheme?locrew_r2l_scheme_kindNoneind;define_individual_scheme?locrew_r2l_dep_scheme_kindNoneind;define_individual_scheme?locrew_r2l_forward_dep_scheme_kindNoneind;(* These ones expect the equality to be symmetric; the first one also *)(* needs eq *)ignore_error(define_individual_schemerew_l2r_scheme_kindNone)ind;ignore_error(define_individual_scheme?locsym_involutive_scheme_kindNone)ind;ignore_error(define_individual_scheme?locrew_l2r_dep_scheme_kindNone)ind;ignore_error(define_individual_scheme?locrew_l2r_forward_dep_scheme_kindNone)indendletwarn_cannot_build_congruence=CWarnings.create~name:"cannot-build-congruence"~category:CWarnings.CoreCategories.automation(fun()->strbrk"Cannot build congruence scheme because eq is not found")letdeclare_congr_scheme?locind=letenv=Global.env()inifHipattern.is_inductive_equalityenvindthenbeginiftryCoqlib.check_required_libraryCoqlib.logic_module_name;truewithewhenCErrors.noncriticale->falsethendefine_individual_scheme?loccongr_scheme_kindNoneindelsewarn_cannot_build_congruence()endletdeclare_sym_scheme?locind=ifHipattern.is_inductive_equality(Global.env())indthen(* Expect the equality to be symmetric *)ignore_error(define_individual_scheme?locsym_scheme_kindNone)ind(* Scheme command *)(* Boolean on scheme_type cheking if it considered dependent *)letsch_isdep=function|SchemeInduction|SchemeElimination->true|SchemeMinimality|SchemeCase->falseletsch_isrec=function|SchemeInduction|SchemeMinimality->true|SchemeElimination|SchemeCase->false(* Generate suffix for scheme given a target sort *)letscheme_suffix_gen{sch_type;sch_sort}sort=(* The _ind/_rec_/case suffix *)letind_suffix=matchsch_isrecsch_type,sch_sortwith|true,InSProp|true,InProp->"_ind"|true,_->"_rec"|false,_->"_case"in(* SProp and Type have an auxillary ending to the _ind suffix *)letaux_suffix=matchsch_sortwith|InSProp->"s"|InType->"t"|_->""in(* Some schemes are deliminated with _dep or no_dep *)letdep_suffix=matchsch_isdepsch_type,sortwith|true,InProp->"_dep"|false,InSet|false,InType|false,InSProp->"_nodep"|_,_->""inind_suffix^aux_suffix^dep_suffixletsmart_indqid=letind=Smartlocate.smart_global_inductiveqidinifDumpglob.dump()thenDumpglob.add_glob?loc:qid.loc(IndRefind);ind(* Resolve the name of a scheme using an environment and extract some
important data such as the inductive type involved, whether it is a dependent
eliminator and its sort. *)letname_and_process_schemeenv=function|(Someid,{sch_type;sch_qualid;sch_sort})->(id,sch_isdepsch_type,smart_indsch_qualid,sch_sort)|(None,({sch_type;sch_qualid;sch_sort}assch))->(* If no name has been provided, we build one from the types of the ind requested *)letind=smart_indsch_qualidinletsort_of_ind=Indrec.pseudo_sort_family_for_elimind(snd(Inductive.lookup_mind_specifenvind))inletsuffix=scheme_suffix_genschsort_of_indinletnewid=Nameops.add_suffix(Nametab.basename_of_global(Names.GlobRef.IndRefind))suffixinletnewref=CAst.makenewidin(newref,sch_isdepsch_type,ind,sch_sort)letdo_mutual_induction_scheme?(force_mutual=false)env?(isrec=true)l=letsigma,inst=let_,_,ind,_=matchlwith|x::_->x|[]->assertfalseinlet_,ctx=Typeops.type_of_global_in_contextenv(Names.GlobRef.IndRefind)inletu,ctx=UnivGen.fresh_instance_fromctxNoneinletu=EConstr.EInstance.makeuinletsigma=Evd.from_ctx(UState.of_context_setctx)insigma,uinletsigma,lrecspec=List.fold_left_map(funsigma(_,dep,ind,sort)->letsigma,sort=Evd.fresh_sort_in_family~rigid:UnivRigidsigmasortin(sigma,((ind,inst),dep,sort)))sigmalinletsigma,listdecl=ifisrecthenIndrec.build_mutual_induction_schemeenvsigma~force_mutuallrecspecelseList.fold_left_map(funsigma(ind,dep,sort)->letsigma,c=Indrec.build_case_analysis_schemeenvsigmainddepsortinletc,_=Indrec.eval_case_analysiscinsigma,c)sigmalrecspecinletpoly=(* NB: build_mutual_induction_scheme forces nonempty list of mutual inductives
(force_mutual is about the generated schemes) *)let_,_,ind,_=List.hdlinGlobal.is_polymorphic(Names.GlobRef.IndRefind)inletdeclaredecl({CAst.v=fi},dep,ind,sort)=letdecltype=Retyping.get_type_ofenvsigmadeclinletdecltype=EConstr.to_constrsigmadecltypeinletdecl=EConstr.to_constrsigmadeclinletcst=define~polyfisigmadecl(Somedecltype)inletkind=letopenElimschemesinifisrecthenSome(elim_scheme~dep~to_kind:sort)elsematchsortwith|InType->Some(ifdepthencase_depelsecase_nodep)|InProp->Some(ifdepthencasep_depelsecasep_nodep)|InSProp|InSet|InQSort->(* currently we don't have standard scheme kinds for this *)Noneinmatchkindwith|None->()|Somekind->DeclareScheme.declare_scheme(Ind_tables.scheme_kind_namekind)(ind,cst)inlet()=List.iter2declarelistdecllinletlrecnames=List.map(fun({CAst.v},_,_,_)->v)linDeclare.fixpoint_messageNonelrecnamesletdo_schemeenvl=letisrec=matchlwith|[_,sch]->sch_isrecsch.sch_type|_->ifList.for_all(fun(_,sch)->sch_isrecsch.sch_type)lthentrueelseCErrors.user_errPp.(str"Mutually defined schemes should be recursive.")inletlnamedepindsort=List.map(name_and_process_schemeenv)lindo_mutual_induction_schemeenv~isreclnamedepindsortletdo_scheme_equality?locmapschid=letmind,_=smart_indidinletdec=matchschwithSchemeBooleanEquality->false|SchemeEquality->trueindeclare_beq_scheme?locmapmind;ifdecthendeclare_eq_decidability?locmapmind(**********************************************************************)(* Combined scheme *)(* Matthieu Sozeau, Dec 2006 *)letlist_split_rev_atindexl=letrecauxiacc=functionhd::tlwhenInt.equaliindex->acc,tl|hd::tl->aux(succi)(hd::acc)tl|[]->failwith"List.split_when: Invalid argument"inaux0[]lletfold_left'f=function[]->invalid_arg"fold_left'"|hd::tl->List.fold_leftfhdtlletmk_coq_andsigma=Evd.fresh_global(Global.env())sigma(Coqlib.lib_ref"core.and.type")letmk_coq_conjsigma=Evd.fresh_global(Global.env())sigma(Coqlib.lib_ref"core.and.conj")letmk_coq_prodsigma=Evd.fresh_global(Global.env())sigma(Coqlib.lib_ref"core.prod.type")letmk_coq_pairsigma=Evd.fresh_global(Global.env())sigma(Coqlib.lib_ref"core.prod.intro")letbuild_combined_schemeenvschemes=letsigma=Evd.from_envenvinletsigma,defs=List.fold_left_map(funsigmacst->letsigma,c=Evd.fresh_constant_instanceenvsigmacstinsigma,(c,Typeops.type_of_constant_inenvc))sigmaschemesinletfind_inductivety=let(ctx,arity)=decompose_prodtyinlet(_,last)=List.hdctxinmatchConstr.kindlastwith|Constr.App(ind,args)->letind=Constr.destIndindinlet(_,spec)=Inductive.lookup_mind_specifenv(fstind)inctx,ind,spec.mind_nrealargs|_->ctx,Constr.destIndlast,0inlet(c,t)=List.hddefsinletctx,ind,nargs=find_inductivetin(* We check if ALL the predicates are in Prop, if so we use propositional
conjunction '/\', otherwise we use the simple product '*'.
*)letinprop=letinprop(_,t)=Retyping.get_sort_family_ofenvsigma(EConstr.of_constrt)==Sorts.InPropinList.for_allinpropdefsinletmk_and,mk_conj=ifinpropthen(mk_coq_and,mk_coq_conj)else(mk_coq_prod,mk_coq_pair)in(* Number of clauses, including the predicates quantification *)letprods=Termops.nb_prodsigma(EConstr.of_constrt)-(nargs+1)inletsigma,coqand=mk_andsigmainletsigma,coqconj=mk_conjsigmainletrelargs=Termops.rel_vect0prodsinletconcls=List.rev_map(fun(cst,t)->Constr.mkApp(Constr.mkConstUcst,relargs),snd(decompose_prod_nprodst))defsinletconcl_bod,concl_typ=fold_left'(fun(accb,acct)(cst,x)->Constr.mkApp(EConstr.to_constrsigmacoqconj,[|x;acct;cst;accb|]),Constr.mkApp(EConstr.to_constrsigmacoqand,[|x;acct|]))conclsinletctx,_=list_split_rev_atprods(List.rev_map(fun(x,y)->Context.Rel.Declaration.LocalAssum(x,y))ctx)inlettyp=List.fold_left(fundc->Term.mkProd_wo_LetIncd)concl_typctxinletbody=it_mkLambda_or_LetInconcl_bodctxinletsigma=Typing.checkenvsigma(EConstr.of_constrbody)(EConstr.of_constrtyp)in(sigma,body,typ)letdo_combined_schemenamecsts=letopenCAstinletsigma,body,typ=build_combined_scheme(Global.env())cstsin(* It is possible for the constants to have different universe
polymorphism from each other, however that is only when the user
manually defined at least one of them (as Scheme would pick the
polymorphism of the inductive block). In that case if they want
some other polymorphism they can also manually define the
combined scheme. *)letpoly=Global.is_polymorphic(Names.GlobRef.ConstRef(List.hdcsts))inignore(define~polyname.vsigmabody(Sometyp));Declare.fixpoint_messageNone[name.v](**********************************************************************)letmap_inductive_block?(locmap=Locmap.defaultNone)fknn=fori=0ton-1doletloc=Ind_tables.Locmap.lookup~locmap(kn,i)inf?loc(kn,i)doneletdeclare_default_schemes?locmapkn=letmib=Global.lookup_mindkninletn=Array.lengthmib.mind_packetsinif!elim_flag&&(mib.mind_finite<>Declarations.BiFinite||!bifinite_elim_flag)&&mib.mind_typing_flags.check_positivethendeclare_induction_schemeskn?locmap;if!case_flagthenmap_inductive_block?locmapdeclare_one_case_analysis_schemeknn;ifis_eq_flag()thentry_declare_beq_schemekn?locmap;if!eq_dec_flagthentry_declare_eq_decidabilitykn?locmap;if!rewriting_flagthenmap_inductive_block?locmapdeclare_congr_schemeknn;if!rewriting_flagthenmap_inductive_block?locmapdeclare_sym_schemeknn;if!rewriting_flagthenmap_inductive_block?locmapdeclare_rewriting_schemesknn