1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531(************************************************************************)(* * 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) *)(************************************************************************)(* This file is about the automatic generation of schemes about
decidable equality, created by Vincent Siles, Oct 2007 *)openUtilopenConstropenVarsopenDeclarationsopenNamesmoduleRelDecl=Context.Rel.Declaration(**********************************************************************)(* Generic synthesis of boolean equality *)exceptionEqNotFoundofinductiveexceptionEqUnknownofstringexceptionUndefinedCstofstringexceptionInductiveWithProductexceptionInductiveWithSortexceptionParameterWithoutEqualityofGlobRef.texceptionNonSingletonPropofinductiveexceptionDecidabilityMutualNotSupportedexceptionNoDecidabilityCoInductiveexceptionConstructorWithNonParametricInductiveTypeofinductiveexceptionDecidabilityIndicesNotSupportedexceptionInternalDependenciesletnamed_hdenvtna=Namegen.named_hdenv(Evd.from_envenv)(EConstr.of_constrt)naletname_assumptionenv=function|RelDecl.LocalAssum(na,t)->RelDecl.LocalAssum(Context.map_annot(named_hdenvt)na,t)|RelDecl.LocalDef(na,c,t)->RelDecl.LocalDef(Context.map_annot(named_hdenvc)na,c,t)letname_contextenvctxt=snd(List.fold_left(fun(env,hyps)d->letd'=name_assumptionenvdin(Environ.push_reld'env,d'::hyps))(env,[])(List.revctxt))(* Some pre declaration of constant we are going to use *)letandb_prop=fun_->UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.bool.andb_prop")letandb_true_intro=fun_->UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.bool.andb_true_intro")(* We avoid to use lazy as the binding of constants can change *)letbb()=UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.bool.type")lettt()=UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.bool.true")letff()=UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.bool.false")leteq()=UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.eq.type")letint63_eqb()=UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"num.int63.eqb")letfloat64_eqb()=UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"num.float.leibniz.eqb")letsumbool()=UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.sumbool.type")letandb=fun_->UnivGen.constr_of_monomorphic_global(Global.env())(Rocqlib.lib_ref"core.bool.andb")letinduct_onc=Induction.inductionfalseNonecNoneNoneletdestruct_onc=Induction.destructfalseNonecNoneNoneletdestruct_on_usingcid=letopenTactypesinInduction.destructfalseNonec(Some(CAst.make@@IntroOrPattern[[CAst.make@@IntroNamingIntroAnonymous];[CAst.make@@IntroNaming(IntroIdentifierid)]]))Noneletdestruct_on_ascl=Induction.destructfalseNonec(Some(CAst.makel))Noneletinj_flags=Some{Equality.keep_proof_equalities=true;(* necessary *)Equality.injection_pattern_l2r_order=true;(* does not matter here *)}letmy_discr_tac=Equality.discr_tacfalseNoneletmy_inj_tacx=Equality.injinj_flagsNonefalseNone(EConstr.mkVarx,NoBindings)(* reconstruct the inductive with the correct de Bruijn indexes *)letmkFullIndenv(ind,u)n=letmib=Environ.lookup_mind(fstind)envinmkApp(mkIndU(ind,u),Context.Rel.instancemkRelnmib.mind_params_ctxt)letmkPartialIndenv(ind,u)n=letmib=Environ.lookup_mind(fstind)envinlet_,recparams_ctx=Inductive.inductive_nonrec_rec_paramdecls(mib,u)inmkApp(mkIndU(ind,u),Context.Rel.instancemkRelnrecparams_ctx)letname_X=Context.make_annot(Name(Id.of_string"X"))Sorts.Relevantletname_Y=Context.make_annot(Name(Id.of_string"Y"))Sorts.Relevantletmk_eqb_overu=mkProd(name_X,u,(mkProd(name_Y,lift1u,bb())))letcheck_bool_is_defined()=ifnot(Rocqlib.has_ref"core.bool.type")thenraise(UndefinedCst"bool")letcheck_no_indicesmib=ifArray.exists(funmip->mip.mind_nrealargs<>0)mib.mind_packetsthenraiseDecidabilityIndicesNotSupportedletis_irrelevantenvc=matchkind(EConstr.Unsafe.to_constr(Retyping.get_type_ofenv(Evd.from_envenv)(EConstr.of_constrc)))with|SortSProp->true|_->falseletget_schemehandlekind=matchInd_tables.local_lookup_schemehandlekindwith|None->assertfalse|Somec->cletbeq_scheme_kind_aux=ref(fun_->failwith"Undefined")letget_inductive_deps~nopropenvkn=(* fetching the mutual inductive body *)letmib=Environ.lookup_mindknenvin(* number of params in the type *)check_no_indicesmib;letenv=Environ.push_rel_contextmib.mind_params_ctxtenvinletsigma=Evd.from_envenvinletget_deps_oneaccuimip=(* This function is only trying to recursively compute the inductive types
appearing as arguments of the constructors. This is done to support
equality decision over hereditarily first-order types. It could be
performed in a much cleaner way, e.g. using the kernel normal form of
constructor types and kernel whd_all for the argument types. *)letrecauxenvaccuc=let(c,a)=Reductionops.whd_all_stackenvsigmacinmatchEConstr.kindsigmacwith|Cast(x,_,_)->auxenvaccu(EConstr.applist(x,a))|App_->assertfalse|Ind((kn',_asind),_)->ifEnviron.QMutInd.equalenvknkn'then(* Example: Inductive T A := C : T (option A) -> T A. *)List.fold_left(auxenv)accuaelselet_,mip=Inductive.lookup_mind_specifenvindin(* Types in SProp have trivial equality and are skipped *)ifmatchmip.mind_aritywithRegularArity{mind_sort=SProp}->true|_->falsethenList.fold_left(auxenv)accuaelseList.fold_left(auxenv)(kn'::accu)a|Const(kn,u)->(matchEnviron.constant_opt_value_inenv(kn,EConstr.EInstance.kindsigmau)with|Somec->auxenvaccu(EConstr.applist(EConstr.of_constrc,a))|None->accu)|Rel_|Var_|Sort_|Prod_|Lambda_|LetIn_|Proj_|Construct_|Case_|CoFix_|Fix_|Meta_|Evar_|Int_|Float_|String_|Array_->Termops.fold_constr_with_full_bindersenvsigmaEConstr.push_relauxenv(List.fold_left(auxenv)accua)cinletfoldiaccu(constr_ctx,_)=letconstr_ctx,_=List.chopmip.mind_consnrealdecls.(i)constr_ctxinletrecfoldenvaccu=function|[]->env,accu|decl::ctx->letenv,accu=foldenvaccuctxinlett=Context.Rel.Declaration.get_typedeclinEnviron.push_reldeclenv,(ifnoprop&&is_irrelevantenvtthenaccuelseauxenvaccu(EConstr.of_constrt))insnd(foldenvaccuconstr_ctx)inArray.fold_left_ifoldaccumip.mind_nf_lcinArray.fold_left_i(funiaccumip->get_deps_oneaccuimip)[]mib.mind_packets(** A compact data structure to remember for each declaration of the
context if it is a type and comes with a Boolean equality; if it
comes with an equality we remember the integer to subtract to the
de Bruijn indices of the binder to get the equality *)typeeq_status=|End(* int is the number of consecutive declarations without an equality *)|WithoutEqofint*eq_status(* list is the list of shifts for consecutive declarations with an equality *)|WithEqofintlist*eq_statusletadd_eq_status_no=function|WithEq_|Endass->WithoutEq(1,s)|WithoutEq(n,s)->WithoutEq(n+1,s)letset_eq_status_yesnqs=letrecauxn=function|WithoutEq(p,End)whenInt.equalnp->WithoutEq(p-1,WithEq([q],End))|WithoutEq(p,WithEq(l,s))whenInt.equalnp->WithoutEq(p-1,WithEq(q::l,s))|WithoutEq(p,s)whenn<p->WithoutEq(n-1,WithEq([q],WithoutEq(p-n,s)))|WithoutEq(p,s)whenInt.equaln1->WithEq([q],WithoutEq(p-1,s))|WithoutEq(p,s)->WithoutEq(p,aux(n-p)s)|WithEq(l,s)->WithEq(l,aux(n-List.lengthl)s)|End->assertfalseinauxnsletrechas_decl_equalitynstatus=matchn,statuswith|p,WithEq(l,s)whenp<=List.lengthl->Some(List.nthl(p-1))|p,WithEq(l,s)->has_decl_equality(p-List.lengthl)s|p,WithoutEq(n,s)whenp<=n->None|p,WithoutEq(n,s)->has_decl_equality(p-n)s|_,End->assertfalse(** The reallocation of variables to be done during the translation:
[env] is the current env at the corresponding step of the translation
[lift] is the lift for the original variables
[eq_status] tells how to get the equality associated with a variable if any
[ind_pos] tells the position of recursive calls (it could have
been avoided by replacing the recursive occurrences of ind in an
inductive definition by variables *)typeenv_lift={env:Environ.env;(* Gamma *)lift:Esubst.lift;(* lift : Gamma + Gamma_eq |- Gamma *)eq_status:eq_status;ind_pos:((MutInd.t*int*rel_context*int)*int)option;}letlift_ind_posn=Option.map(fun(ind,k)->(ind,k+n))letempty_env_liftenv={env=env;lift=Esubst.el_id;eq_status=End;ind_pos=None;}letpush_env_liftdeclenv_lift={env=Environ.push_reldeclenv_lift.env;lift=Esubst.el_liftenv_lift.lift;eq_status=add_eq_status_noenv_lift.eq_status;ind_pos=lift_ind_pos1env_lift.ind_pos;}letset_replicatenqenv_lift={env=env_lift.env;lift=env_lift.lift;eq_status=set_eq_status_yesnqenv_lift.eq_status;ind_pos=env_lift.ind_pos;}letshiftn_env_liftnenv_lift={env_liftwithlift=Esubst.el_shftn(Esubst.el_liftnnenv_lift.lift);ind_pos=lift_ind_posnenv_lift.ind_pos;}letfind_ind_env_liftenv_lift(mind,i)=matchenv_lift.ind_poswith|Some((mind',nrecparams,recparamsctx,nb_ind),n)whenEnviron.QMutInd.equalenv_lift.envmindmind'->Some(nrecparams,recparamsctx,n+nb_ind-i)|_->Noneletshift_fix_env_liftindnrecparamsrecparamsctxnb_indenv_lift={env=env_lift.env;lift=Esubst.el_shftnb_indenv_lift.lift;eq_status=env_lift.eq_status;ind_pos=Some((ind,nrecparams,recparamsctx,nb_ind),0)}letpush_rec_env_liftrecdefenv_lift=letn=Array.length(pi1recdef)in{env=Environ.push_rec_typesrecdefenv_lift.env;lift=Esubst.el_liftnnenv_lift.lift;eq_status=add_eq_status_noenv_lift.eq_status;ind_pos=lift_ind_posnenv_lift.ind_pos;}letdest_lam_assum_expandenvc=letctx,c=Reduction.whd_decompose_lambda_declsenvcinifList.is_emptyctxthenctx,celselett=EConstr.Unsafe.to_constr(Retyping.get_type_of(Environ.push_rel_contextctxenv)(Evd.from_envenv)(EConstr.of_constrc))inletctx',_=Reduction.whd_decompose_prod_declsenvtinctx'@ctx,mkApp(lift(Context.Rel.lengthctx')c,Context.Rel.instancemkRel0ctx')letpred_contextenvciparamsunas=letmib,mip=Inductive.lookup_mind_specifenvci.ci_indinletparamdecl=Vars.subst_instance_contextumib.mind_params_ctxtinletparamsubst=Vars.subst_of_rel_context_instanceparamdeclparamsinletrealdecls,_=List.chopmip.mind_nrealdeclsmip.mind_arity_ctxtinletself=letargs=Context.Rel.instancemkRel0mip.mind_arity_ctxtinletinst=UVars.Instance.(abstract_instance(lengthu))inmkApp(mkIndU(ci.ci_ind,inst),args)inletna=Context.make_annotAnonymousmip.mind_relevanceinletrealdecls=RelDecl.LocalAssum(na,self)::realdeclsinInductive.instantiate_contextuparamsubstnasrealdeclsletbranch_contextenvciparamsunasi=letmib,mip=Inductive.lookup_mind_specifenvci.ci_indinletparamdecl=Vars.subst_instance_contextumib.mind_params_ctxtinletparamsubst=Vars.subst_of_rel_context_instanceparamdeclparamsinletctx,_=List.chopmip.mind_consnrealdecls.(i)(fstmip.mind_nf_lc.(i))inInductive.instantiate_contextuparamsubstnasctxletbuild_beq_scheme_depsenvkn=letinds=get_inductive_deps~noprop:trueenvkninList.map(funind->Ind_tables.SchemeMutualDep(ind,!beq_scheme_kind_aux()))indsletbuild_beq_schemeenvhandlekn=check_bool_is_defined();(* predef coq's boolean type *)(* here I leave the Naming thingy so that the type of
the function is more readable for the user *)leteqName=Context.map_annot(function|Names->Name(Id.of_string("eq_"^(Id.to_strings)))|Anonymous->Name(Id.of_string"eq_A"))in(* The Boolean equality translation is a parametricity translation
where each type T is interpreted as the pair of:
- a (possibly degenerate) predicate T_R in Type over T (i.e. T_R : T->Type)
- when T is decidable, a Boolean equality T_E over (i.e. T_E :
option (T->T->bool) where None means not decidable, that is, at
worst, unknown to be decidable)
This generalizes into an interpretation of each term M:T as:
- an inhabitant [|M|] of T_R M
by setting for sort s:
- s_R := \T:s.{R:T->s ; E:option (T->T->bool)} and
- s_E := None
so that types T:s are indeed interpreted as a pair, namely by:
- [|T|] := {R:=T_R; E:=T_E} : s_R T
and, in particular:
- [|Type(n)|] := {R:=Type(n)_R; E:=Type(n)_E) : Type(n+1)_R Type(n)
In practice, to have simpler schemes, we won't support here the
full hierarchy of sorts. That is, we assume that type parameters
of a type will be instantiated only by small types (i.e. not
containing sorts). This makes sense since equality on large types
is anyway not decidable in the general case [*].
Now, it happens that several parts of the translation are
degenerate. For instance, if T is a small type (not containing
sorts), then T_R M, which expresses that M realizes T, is a
singleton for all M (we assume functional extensionality to treat
the case of dependent product types). Therefore, M_T does not
need to be defined in this case. Conversely, if T is not small,
it is not decidable and T_E will be None.
This means that at least T_R is degenerate or T_E is None and
this also means that for M:T with degenerate T_R, we don't need
to compute [|M|].R
This further means that when translating a variable x:T with T
small, it can just be translated to x:T without requiring the
trivial information that T_R x is inhabited.
Similarly for types T of the form [forall X, (forall Y ...) ... Y args]
based on the assumption [*] that Y is instantiated only by small
functorial types for which (Y args)_R would be degenerate.
Similarly, based on the restriction above [*] that parameters are
instantiated by small types, when translating a variable x:T with
T an arity, i.e. of the form [... -> Type] (or at worst
[... -> Type*Type] etc.), we can assume x to be instantiated by a
small functorial type whose R translation is degenerate.
It remains the declarations of the form X:T for T of the form
[forall X, ... X args] where X is in negative position of a
dependent product. If such X is instantiated by a large type in
the definition, as in
[Inductive I (F:forall X:Type, X->X) (B:F Type nat) := C : B -> I F B],
we give up. Otherwise said, we support only the case when `X`is
instantiated by a small type.
Eventually, we thus need two translations:
- T_R when T is large and it does not need to go under
applicative subterms since subterms [X args] are considered
small by assumption [*]
- T_E when T is small which needs to go under subterms and which
thus needs to be generalized into a translation M_E : T_R.E
whenever T is detected as decidable (in which case, T_R.E is
typically of the form T->T->bool or of the form
(T.1->T.1->bool)*(T.2->T.2->bool), etc.)
Below, the first translation is called [translate_type_eq] and
the second [translate_term_eq]. Additionally, there is a copy-cat
translation called "translate_term" that lifts M in the typing context
of M_R.
The function [translate_type_eq] takes as input a type T and a
term M of type T and it returns T_R M.
For M of type T, the function [translate_term_eq M] returns an
object of type term T_R M, that is, when M is itself some type U,
an object of type U->U->bool.
Note that we don't use an option type for non-decidable types but
instead raises an exception whenever a type is not detected as
decidable.
Future work might support:
- exotic types such as
[Inductive I (F:forall X:Type, X->X) (B:F Type nat) := C : B -> I F B]
- types with invertible indices like listn
- dependent products over finite types (e.g. over bool->bool), and
more generally compact types whose equality is decidable (see Escardo-Oliva)
*)letrectranslate_type_eqenv_liftnact=letctx,t=Reduction.whd_decompose_prod_declsenvtinletenv_lift',ctx_eq=translate_context_eqenv_liftctxinletinst=Array.map(translate_termenv_lift')(Context.Rel.instancemkRel0ctx)inletenv_lift''=shiftn_env_lift(Context.Rel.lengthctx_eq)env_liftinletc=mkApp(translate_termenv_lift''c,inst)inletc=matchkindtwith|Sort_->Some(mk_eqb_overc)|Prod_|LetIn_->assertfalse(* [s] is necessaritly a sort *)|Cast(t,k,s)->beginmatchtranslate_type_eqenv_lift'nactwith|None->None|Somet->Some(mkCast(t,k,mkProd(na,t,c)))end(* TODO: take into account situations like (P:Type * Type) which
could be translated into (fst P->fst P>bool)*(snd P->snd
P->bool); to be done in parallel with preserving the types in
Proj/Construct/CoFix *)|Ind_->None|Array_->None(* We assume references to be references to small types and thus
to types with singleton realizability predicate; to support
references to large types, see comments above for the full
translation *)|App_|Rel_|Var_|Const_->None(* The restricted translation translates only types *)|Lambda_|Construct_->assertfalse|Case(ci,u,pms,((pnames,p),r),iv,tm,lbr)->letenv_lift_pred=shiftn_env_lift(Array.lengthpnames)env_liftinlett=mkCase(ci,u,Array.map(translate_termenv_lift_pred)pms,(translate_term_with_bindersenv_lift_pred(pnames,p),r),Constr.map_invert(translate_termenv_lift_pred)iv,mkRel1,Array.map(translate_term_with_bindersenv_lift_pred)lbr)in(* in the restricted translation, only types are translated and
the return predicate is necessarily a type *)letp=mkProd(Context.anonR,t,p)inletlbr=Array.mapi(funi(names,t)->letctx=branch_contextenvcipmsunamesiinletenv_lift'=List.fold_rightpush_env_liftctxenv_liftinmatchtranslate_type_eqenv_lift'na(mkRel1)twith|None->None|Somet_eq->Some(names,mkLambda(na,t,t_eq)))lbrinifArray.for_allOption.has_somelbrthenletlbr=Array.mapOption.getlbrinletcase=mkCase(ci,u,pms,((pnames,p),r),iv,translate_termenv_lifttm,lbr)inSome(mkApp(case,[|c|]))elseNone(* TODO: in parallel with traversing Fix in translate_term_eq to
look for types, traverse Fix to look for Type here *)|Fix_->None(* Not building a type *)|Proj_|CoFix_|Int_|Float_|String_->None|Meta_|Evar_->assertfalse(* kernel terms *)inOption.map(func->Term.it_mkProd_or_LetIncctx_eq)candtranslate_term_eqenv_liftc=letctx,c=dest_lam_assum_expandenv_lift.envcinletenv_lift,ctx=translate_context_eqenv_liftctxinletc=matchConstr.kindcwith|Relx->(matchhas_decl_equalityxenv_lift.eq_statuswith|Somen->Some(mkRel(Esubst.reloc_relxenv_lift.lift-n))|None->None)|Varx->ifReduction.is_arityenv(Typeops.type_of_variableenvx)then(* Support for working in a context with "eq_x : x -> x -> bool" *)leteid=Id.of_string("eq_"^(Id.to_stringx))inlet()=tryignore(Environ.lookup_namedeidenv)withNot_found->raise(ParameterWithoutEquality(GlobRef.VarRefx))inSome(mkVareid)elseNone|Cast(c,k,t)->beginmatchtranslate_term_eqenv_liftc,translate_type_eqenv_liftContext.anonRctwith|Somec,Somet->Some(mkCast(c,k,t))|None,None->None|(None|Some_),_->assertfalseend|Lambda_|LetIn_->assertfalse|App(f,args)->beginletf,args=matchkindfwith|Ind(ind',_)->(matchfind_ind_env_liftenv_liftind'with|Some(nrecparams,_,n)whenArray.lengthargs>=nrecparams->Some(mkReln),Array.subargsnrecparams(Array.lengthargs-nrecparams)|_->translate_term_eqenv_liftf,args)|Const(kn,u)->(matchEnviron.constant_opt_value_inenv(kn,u)with|Somec->translate_term_eqenv_lift(mkApp(c,args)),[||]|None->translate_term_eqenv_liftf,args)|_->translate_term_eqenv_liftf,argsinmatchfwith|Somef->Some(mkApp(f,translate_arguments_eqenv_liftargs))|None->Noneend|Ind(ind',u)->beginmatchfind_ind_env_liftenv_liftind'with|Some(_,recparamsctx,n)->Some(Term.it_mkLambda_or_LetIn(mkReln)(translate_contextenv_liftrecparamsctx))|None->trySome(mkConstU(get_schemehandle(!beq_scheme_kind_aux())ind',u))withNot_found->raise(EqNotFoundind')end|Const(kn,uascst)->ifEnviron.is_int63_typeenvknthenSome(int63_eqb())elseifEnviron.is_float64_typeenvknthenSome(float64_eqb())elseifEnviron.is_array_typeenvknthen(* TODO *)raise(ParameterWithoutEquality(GlobRef.ConstRefkn))else(matchEnviron.constant_opt_value_inenv(kn,u)with|Somec->translate_term_eqenv_liftc|None->ifReduction.is_arityenv(Typeops.type_of_constant_inenvcst)then(* Support for working in a context with "eq_x : x -> x -> bool" *)(* Needs Hints, see test suite *)leteq_lbl=Label.make("eq_"^Label.to_string(Constant.labelkn))inletkneq=Constant.change_labelkneq_lblinifEnviron.mem_constantkneqenvthenlet_=Environ.constant_opt_value_inenv(kneq,u)inSome(mkConstU(kneq,u))elseraise(ParameterWithoutEquality(GlobRef.ConstRefkn))elseNone)(* TODO: in parallel with preserving Type for Ind in
translate_type_eq, preserve the types in Construct/CoFix *)|Proj_|Construct_|CoFix_->None|Case(ci,u,pms,((pnames,p),r),iv,tm,lbr)->letpctx=pred_contextenvcipmsupnamesinletenv_lift_pred=List.fold_rightpush_env_liftpctxenv_liftinletn=Array.lengthpnamesinletc=mkCase(ci,u,Array.map(liftn)pms,((pnames,liftnn(n+1)p),r),Constr.map_invert(liftn)iv,mkRel1,Array.map(fun(names,br)->(names,letq=Array.lengthnamesinliftnn(n+q+1)br))lbr)inletp=translate_type_eqenv_lift_predContext.anonRcpinletlbr=Array.mapi(funi(names,t)->letctx=branch_contextenvcipmsunamesiinletenv_lift'=List.fold_rightpush_env_liftctxenv_liftinmatchtranslate_term_eqenv_lift'twith|None->None|Somet_eq->Some(names,t_eq))lbrinifArray.for_allOption.has_somelbr&&Option.has_somepthenletlbr=Array.mapOption.getlbrinSome(mkCase(ci,u,pms,((pnames,Option.getp),r),iv,translate_termenv_lifttm,lbr))elseNone|Fix((recindxs,i),(names,typarray,bodiesasrecdef))->let_=(* Almost work: would need:
1. that the generated fix has an eq_status registration
telling that an original recursive call should be
interpreted as the pair of the whole fix and of the
translated recursive call building the equality
2. something to do around either packaging the type with
its equality, or begin able for a match to have a return
predicate different though convertible to itself, namely
here a fix of match (see test-suite) *)letmkfixj=mkFix((recindxs,j),recdef)inlettyparray=Array.mapi(funi->translate_type_eqenv_liftContext.anonR(mkfixi))typarrayinletenv_lift_types=push_rec_env_liftrecdefenv_liftinletbodies=Array.map(translate_term_eqenv_lift_types)bodiesinifArray.for_allOption.has_somebodies&&Array.for_allOption.has_sometyparraythenletbodies=Array.mapOption.getbodiesinlettyparray=Array.mapOption.gettyparrayinSome(mkFix((recindxs,i),(names,typarray,bodies)))elseNoneinNone|Sort_->raiseInductiveWithSort(* would require a more sophisticated translation *)|Prod_->raiseInductiveWithProduct(* loss of decidable if uncountable domain *)|Meta_|Evar_->None(* assert false! *)|Int_|Float_|String_|Array_->NoneinOption.map(func->Term.it_mkLambda_or_LetIncctx)c(* Translate context by adding a context of Boolean equalities for each type argument
Example of translated context:
(F : (U -> U) -> nat -> U)
(eq_F : forall G, (forall A, eq A -> eq (G A)) -> nat -> eq (F G)) *)andtranslate_context_eqenv_liftctx=letctx=name_contextenv_lift.envctxinlet(env_lift_ctx,nctx_eq,ctx_with_eq)=List.fold_right(fundecl(env_lift,n,ctx)->letenv_lift=push_env_liftdeclenv_liftinletenv_lift'=shiftn_env_lift(n-1)env_liftinmatchdeclwith|RelDecl.LocalDef(na,c,t)->(matchtranslate_term_eqenv_lift'(lift1c),translate_type_eqenv_lift'na(mkRel1)(lift1t)with|Someeq_c,Someeq_typ->(set_replicate1nenv_lift,n,RelDecl.LocalDef(eqNamena,eq_c,eq_typ)::ctx)|None,None->(env_lift,n-1,ctx)|(None|Some_),_->assertfalse)|RelDecl.LocalAssum(na,t)->matchtranslate_type_eqenv_lift'na(mkRel1)(lift1t)with|Someeq_typ->(set_replicate1nenv_lift,n,RelDecl.LocalAssum(eqNamena,eq_typ)::ctx)|None->(env_lift,n-1,ctx))ctx(env_lift,Context.Rel.lengthctx,ctx)inshiftn_env_liftnctx_eqenv_lift_ctx,ctx_with_eq(* Translate arguments by adding Boolean equality when relevant
Examples of translated applications:
F (fun A => A) 0
eq_F (fun A => A) (fun A eq_A => eq_A) 0
F (fun A => list A) 0
eq_F (fun A => list A) (fun A eq_A => eq_list A eq_A) 0 *)andtranslate_arguments_eqenv_liftargs=letargs'=Array.map(translate_termenv_lift)argsinleteq_args=Array.of_list(List.map_filter(translate_term_eqenv_lift)(Array.to_listargs))inArray.appendargs'eq_args(* Copy-cat translation with relocation *)andtranslate_termenv_liftc=exliftnenv_lift.liftcandtranslate_contextenv_liftctx=Context.Rel.map_with_binders(funi->translate_term(shiftn_env_liftienv_lift))ctxandtranslate_term_with_bindersenv_lift(names,c)=(names,translate_term(shiftn_env_lift(Array.lengthnames)env_lift)c)in(* Starting translating the inductive block to Boolean equalities;
Morally corresponds to the Ind case of translate_term_eq *)(* fetching the mutual inductive body *)letmib=Environ.lookup_mindknenvin(* Setting universes *)letauctx=Declareops.universes_contextmib.mind_universesinletu,ctx=UnivGen.fresh_instance_fromauctxNoneinletuctx=UState.from_envenvinletuctx=UState.merge_sort_context~sideff:falseUState.univ_rigiductxctxin(* number of inductives in the mutual *)letnb_ind=Array.lengthmib.mind_packetsinlettruly_recursive=letopenDeclarationsinletis_recra=matchDeclareops.dest_recargrawithMrec_->true|Norec->falseinArray.exists(funmip->Array.exists(List.existsis_rec)(Declareops.dest_subtermsmip.mind_recargs))mib.mind_packetsin(* params context divided *)letnonrecparams_ctx,recparams_ctx=Inductive.inductive_nonrec_rec_paramdecls(mib,u)inletparams_ctx=nonrecparams_ctx@recparams_ctxinletnparamsdecls=Context.Rel.lengthparams_ctxincheck_no_indicesmib;letenv_lift_recparams,recparams_ctx_with_eqs=translate_context_eq(empty_env_liftenv)recparams_ctxinletenv_lift_recparams_fix,fix_ctx,names,types=matchmib.mind_finitewith|CoFinite->raiseNoDecidabilityCoInductive|Finitewhentruly_recursive||nb_ind>1(* Hum, there exist non-recursive mutual types... *)->(* rec name *)letrec_namei=(Id.to_string(Array.getmib.mind_packetsi).mind_typename)^"_eqrec"inletnames=Array.initnb_ind(funi->Context.make_annot(Name(Id.of_string(rec_namei)))Sorts.Relevant)inlettypes=Array.initnb_ind(funi->Option.get(translate_type_eqenv_lift_recparamsContext.anonR(mkPartialIndenv((kn,i),u)0)(Term.it_mkProd_or_LetIn(*any sort:*)mkSetnonrecparams_ctx)))inletfix_ctx=List.rev(Array.to_list(Array.map2(funnat->RelDecl.LocalAssum(na,t))namestypes))inshift_fix_env_liftknmib.mind_nparams_recrecparams_ctxnb_indenv_lift_recparams,fix_ctx,names,types|Finite|BiFinite->env_lift_recparams,[],[||],[||]inletenv_lift_recparams_fix_nonrecparams,nonrecparams_ctx_with_eqs=translate_context_eqenv_lift_recparams_fixnonrecparams_ctxinletmake_one_eqcur=(* construct the "fun A B ... N, eqA eqB eqC ... N => fixpoint" part *)letind=(kn,cur)inletindu=(ind,u)inlettomatch_ctx=RelDecl.[LocalAssum(name_Y,translate_term(shiftn_env_lift1env_lift_recparams_fix_nonrecparams)(mkFullIndenvindu0));LocalAssum(name_X,translate_termenv_lift_recparams_fix_nonrecparams(mkFullIndenvindu0))]inletenv_lift_recparams_fix_nonrecparams_tomatch=shiftn_env_lift2env_lift_recparams_fix_nonrecparamsin(* current inductive we are working on *)letopenTerminletpred=letcur_packet=mib.mind_packets.(cur)in(* Inductive toto : [rettyp] := *)letrettyp=Inductive.type_of_inductive((mib,cur_packet),u)in(* split rettyp in a list without the non rec params and the last ->
e.g. Inductive vec (A:Set) : nat -> Set := ... will do [nat] *)let_,rettyp=decompose_prod_n_declsnparamsdeclsrettypinletrettyp_l,_=decompose_prod_declsrettypin(* construct the predicate for the Case part*)Term.it_mkLambda_or_LetIn(mkLambda(Context.make_annotAnonymousSorts.Relevant,mkFullIndenvindu(List.lengthrettyp_l),(bb())))rettyp_lin(* make_one_eq *)(* do the [| C1 ... => match Y with ... end
...
Cn => match Y with ... end |] part *)letrci=EConstr.ERelevance.relevantin(* returning a boolean, hence relevant *)letopenInductiveopsinletconstrs=letparams=Context.Rel.instance_listEConstr.mkRel0params_ctxinget_constructorsenv(make_ind_family(on_sndEConstr.EInstance.makeindu,params))inletmake_andb_list=function|[]->tt()|eq::eqs->List.fold_left(funeqseq->mkApp(andb(),[|eq;eqs|]))eqeqsinletbody=matchEnviron.get_projectionsenvindwith|Someprojs->(* A primitive record *)letnb_cstr_args=List.lengthconstrs.(0).cs_argsinlet_,_,eqs=List.fold_right(fundecl(ndx,env_lift,l)->letdecl=EConstr.Unsafe.to_rel_decldeclinletenv_lift'=push_env_liftdeclenv_liftinmatchdeclwith|RelDecl.LocalDef(na,b,t)->(ndx-1,env_lift',l)|RelDecl.LocalAssum(na,cc)->ifis_irrelevantenv_lift.envccthen(ndx-1,env_lift',l)elseifVars.noccur_between1(nb_cstr_args-ndx)ccthenletcc=lift(ndx-nb_cstr_args)ccinmatchtranslate_term_eqenv_lift_recparams_fix_nonrecparams_tomatchccwith|None->raise(EqUnknown"type")(* A supported type should have an eq *)|SomeeqA->letproj,relevance=projs.(nb_cstr_args-ndx)inletproj=Projection.makeprojtruein(ndx-1,env_lift',mkApp(eqA,[|mkProj(proj,relevance,mkRel2);mkProj(proj,relevance,mkRel1)|])::l)elseraiseInternalDependencies)constrs.(0).cs_args(nb_cstr_args,env_lift_recparams_fix_nonrecparams_tomatch,[])inmake_andb_listeqs|None->(* An inductive type *)letci=make_case_infoenvindMatchStyleinletnconstr=Array.lengthconstrsinletar=Array.initnconstr(funi->letnb_cstr_args=List.lengthconstrs.(i).cs_argsinletenv_lift_recparams_fix_nonrecparams_tomatch_csargsi=shiftn_env_liftnb_cstr_argsenv_lift_recparams_fix_nonrecparams_tomatchinletar2=Array.initnconstr(funj->letenv_lift_recparams_fix_nonrecparams_tomatch_csargsij=shiftn_env_liftnb_cstr_argsenv_lift_recparams_fix_nonrecparams_tomatch_csargsiinletcc=ifInt.equalijthenlet_,_,eqs=List.fold_right(fundecl(ndx,env_lift,l)->letdecl=EConstr.Unsafe.to_rel_decldeclinletenv_lift'=push_env_liftdeclenv_liftinmatchdeclwith|RelDecl.LocalDef(na,b,t)->(ndx-1,env_lift',l)|RelDecl.LocalAssum(na,cc)->ifis_irrelevantenv_lift.envccthen(ndx-1,env_lift',l)elseifVars.noccur_between1(nb_cstr_args-ndx)ccthenletcc=lift(ndx-nb_cstr_args)ccinmatchtranslate_term_eqenv_lift_recparams_fix_nonrecparams_tomatch_csargsijccwith|None->raise(EqUnknown"type")(* A supported type should have an eq *)|SomeeqA->(ndx-1,env_lift',mkApp(eqA,[|mkRel(ndx+nb_cstr_args);mkRelndx|])::l)elseraiseInternalDependencies)constrs.(j).cs_args(nb_cstr_args,env_lift_recparams_fix_nonrecparams_tomatch_csargsij,[])inmake_andb_listeqselseff()inletcs_argsj=translate_contextenv_lift_recparams_fix_nonrecparams_tomatch_csargsi(EConstr.Unsafe.to_rel_contextconstrs.(j).cs_args)inTerm.it_mkLambda_or_LetIncccs_argsj)inletpredj=EConstr.of_constr(translate_termenv_lift_recparams_fix_nonrecparams_tomatch_csargsipred)inletcase=simple_make_case_or_projectenv(Evd.from_envenv)ci(predj,rci)NoInvert(EConstr.mkRel(nb_cstr_args+1))(EConstr.of_constr_arrayar2)inletcs_argsi=translate_contextenv_lift_recparams_fix_nonrecparams_tomatch(EConstr.Unsafe.to_rel_contextconstrs.(i).cs_args)inTerm.it_mkLambda_or_LetIn(EConstr.Unsafe.to_constrcase)cs_argsi)inletpredi=EConstr.of_constr(translate_termenv_lift_recparams_fix_nonrecparams_tomatchpred)inletcase=simple_make_case_or_projectenv(Evd.from_envenv)ci(predi,rci)NoInvert(EConstr.mkRel2)(EConstr.of_constr_arrayar)inEConstr.Unsafe.to_constrcaseinTerm.it_mkLambda_or_LetIn(Term.it_mkLambda_or_LetInbodytomatch_ctx)nonrecparams_ctx_with_eqsin(* build_beq_scheme *)letres=matchmib.mind_finitewith|CoFinite->raiseNoDecidabilityCoInductive|Finitewhentruly_recursive||nb_ind>1(* Hum... *)->letcores=Array.initnb_indmake_one_eqinArray.initnb_ind(funi->letkelim=Inductiveops.elim_sort(mib,mib.mind_packets.(i))inifnot(Sorts.family_leqInSetkelim)thenraise(NonSingletonProp(kn,i));letdecrArg=Context.Rel.lengthnonrecparams_ctx_with_eqsinletfix=mkFix(((Array.makenb_inddecrArg),i),(names,types,cores))inTerm.it_mkLambda_or_LetInfixrecparams_ctx_with_eqs)|Finite|BiFinite->assert(Int.equalnb_ind1);(* If the inductive type is not recursive, the fixpoint is
not used, so let's replace it with garbage *)letkelim=Inductiveops.elim_sort(mib,mib.mind_packets.(0))inifnot(Sorts.family_leqInSetkelim)thenraise(NonSingletonProp(kn,0));[|Term.it_mkLambda_or_LetIn(make_one_eq0)recparams_ctx_with_eqs|]inletuctx=(* infer univ constraints
For instance template poly inductive produces a univ monomorphic scheme
which when applied needs to constrain the universe of its argument
*)letsigma=Evd.from_ctxuctxinletsigma=Array.fold_left(funsigmac->fst@@Typing.type_ofenvsigma(EConstr.of_constrc))sigmaresinEvd.ustatesigmainres,uctxletbeq_scheme_kind=Ind_tables.declare_mutual_scheme_object"beq"~deps:build_beq_scheme_depsbuild_beq_schemelet_=beq_scheme_kind_aux:=fun()->beq_scheme_kind(* This function tryies to get the [inductive] between a constr
the constr should be Ind i or App(Ind i,[|args|])
*)letdestruct_indenvsigmac=letopenEConstrinlet(c,v)=Reductionops.whd_all_stackenvsigmacindestIndsigmac,Array.of_listvletbl_scheme_kind_aux=ref(fun()->failwith"Undefined")letlb_scheme_kind_aux=ref(fun()->failwith"Undefined")(*
In the following, avoid is the list of names to avoid.
If the args of the Inductive type are A1 ... An
then avoid should be
[| lb_An ... lb _A1 (resp. bl_An ... bl_A1)
eq_An .... eq_A1 An ... A1 |]
so from Ai we can find the correct eq_Ai bl_ai or lb_ai
*)(* used in the leib -> bool side*)letdo_replace_lbhandleaavoidnargpq=letopenEConstrinletavoid=Array.of_listaavoidinletdo_argenvsigmahdvoffset=matchkindsigmavwith|Vars->letx=narg*offsetinletn=Array.lengthavoidinletrecfindi=ifId.equalavoid.(n-i)sthenavoid.(n-i-x)else(ifi<nthenfind(i+1)elseCErrors.user_errPp.(str"Var "++Id.prints++str" seems unknown."))inmkVar(find1)|Const(cst,u)->(* Works in specific situations where the args have to be already declared as a
Parameter (see example "J" in test file SchemeEquality.v);
We assume the parameter to have the same polymorphic arity as cst *)letlbl=Label.to_string(Constant.labelcst)inletnewlbl=ifInt.equaloffset1then("eq_"^lbl)else(lbl^"_lb")inletnewcst=Constant.change_labelcst(Label.makenewlbl)inifEnviron.mem_constantnewcstenvthenmkConstU(newcst,u)elseraise(ConstructorWithNonParametricInductiveType(fsthd))|_->raise(ConstructorWithNonParametricInductiveType(fsthd))inProofview.Goal.enterbeginfungl->lettype_of_pq=Tacmach.pf_get_type_ofglpinletsigma=Tacmach.projectglinletenv=Tacmach.pf_envglinlet(ind,uasindu),v=destruct_indenvsigmatype_of_pqinletc=get_schemehandle(!lb_scheme_kind_aux())indinletopenProofview.Notationsinletlb_type_of_p=mkConstU(c,u)inProofview.tclEVARMAP>>=funsigma->letlb_args=Array.append(Array.appendv(Array.Smart.map(funx->do_argenvsigmaindux1)v))(Array.Smart.map(funx->do_argenvsigmaindux2)v)inletapp=ifArray.is_emptylb_argsthenlb_type_of_pelsemkApp(lb_type_of_p,lb_args)inTacticals.tclTHENLIST[Equality.replacepq;Tactics.applyapp;Auto.default_auto]end(* used in the bool -> leb side *)letdo_replace_blhandle(ind,uasindu)aavoidnarglftrgt=letopenEConstrinletavoid=Array.of_listaavoidinletdo_argenvsigmahdvoffset=matchkindsigmavwith|Vars->letx=narg*offsetinletn=Array.lengthavoidinletrecfindi=ifId.equalavoid.(n-i)sthenavoid.(n-i-x)else(ifi<nthenfind(i+1)elseCErrors.user_errPp.(str"Var "++Id.prints++str" seems unknown."))inmkVar(find1)|Const(cst,u)->(* Works in specific situations where the args have to be already declared as a
Parameter (see example "J" in test file SchemeEquality.v)
We assume the parameter to have the same polymorphic arith as cst *)letlbl=Label.to_string(Constant.labelcst)inletnewlbl=ifInt.equaloffset1then("eq_"^lbl)else(lbl^"_bl")inletnewcst=Constant.change_labelcst(Label.makenewlbl)inifEnviron.mem_constantnewcstenvthenmkConstU(newcst,u)elseraise(ConstructorWithNonParametricInductiveType(fsthd))|_->raise(ConstructorWithNonParametricInductiveType(fsthd))inletrecauxl1l2=match(l1,l2)with|(t1::q1,t2::q2)->Proofview.Goal.enterbeginfungl->letsigma=Tacmach.projectglinletenv=Tacmach.pf_envglinifEConstr.eq_constrsigmat1t2thenauxq1q2else(lettt1=Tacmach.pf_get_type_ofglt1inlet(ind',uasindu),v=trydestruct_indenvsigmatt1(* trick so that the good sequence is returned*)withewhenCErrors.noncriticale->indu,[||]inifEnviron.QInd.equalenvind'indthenTacticals.tclTHENLIST[Equality.replacet1t2;Auto.default_auto;auxq1q2]else(letc=get_schemehandle(!bl_scheme_kind_aux())ind'inletbl_t1=mkConstU(c,u)inletbl_args=Array.append(Array.appendv(Array.Smart.map(funx->do_argenvsigmaindux1)v))(Array.Smart.map(funx->do_argenvsigmaindux2)v)inletapp=ifArray.is_emptybl_argsthenbl_t1elsemkApp(bl_t1,bl_args)inTacticals.tclTHENLIST[Equality.replace_byt1t2(Tacticals.tclTHEN(Tactics.applyapp)(Auto.default_auto));auxq1q2]))end|([],[])->Proofview.tclUNIT()|_->Tacticals.tclZEROMSGPp.(str"Both side of the equality must have the same arity.")inletopenProofview.NotationsinProofview.tclEVARMAP>>=funsigma->begintryProofview.tclUNIT(destAppsigmalft)withDestKO->Tacticals.tclZEROMSGPp.(str"replace failed.")end>>=fun(ind1,ca1)->begintryProofview.tclUNIT(destAppsigmargt)withDestKO->Tacticals.tclZEROMSGPp.(str"replace failed.")end>>=fun(ind2,ca2)->begintryProofview.tclUNIT(fst(destIndsigmaind1))withDestKO->begintryProofview.tclUNIT(fst(fst(destConstructsigmaind1)))withDestKO->Tacticals.tclZEROMSGPp.(str"The expected type is an inductive one.")endend>>=fun(sp1,i1)->begintryProofview.tclUNIT(fst(destIndsigmaind2))withDestKO->begintryProofview.tclUNIT(fst(fst(destConstructsigmaind2)))withDestKO->Tacticals.tclZEROMSGPp.(str"The expected type is an inductive one.")endend>>=fun(sp2,i2)->Proofview.tclENV>>=funenv->ifnot(Environ.QMutInd.equalenvsp1sp2)||not(Int.equali1i2)thenTacticals.tclZEROMSGPp.(str"Eq should be on the same type")elseaux(Array.to_listca1)(Array.to_listca2)(*
create, from a list of ids [i1,i2,...,in] the list
[(in,eq_in,in_bl,in_al),,...,(i1,eq_i1,i1_bl_i1_al )]
*)letlist_idl=List.fold_left(funadecl->lets'=matchRelDecl.get_namedeclwithNames->Id.to_strings|Anonymous->"A"in(Id.of_strings',Id.of_string("eq_"^s'),Id.of_string(s'^"_bl"),Id.of_string(s'^"_lb"))::a)[]lletavoid_of_list_idlist_id=List.fold_left(funavoid(s,seq,sbl,slb)->List.fold_left(funavoidid->Id.Set.addidavoid)avoid[s;seq;sbl;slb])Id.Set.emptylist_id(*
build the right eq_I A B.. N eq_A .. eq_N
*)leteqIhandle(ind,u)list_id=leteA=Array.of_list((List.map(fun(s,_,_,_)->mkVars)list_id)@(List.map(fun(_,seq,_,_)->mkVarseq)list_id))ande=mkConstU(get_schemehandlebeq_scheme_kindind,u)inmkApp(e,eA)(**********************************************************************)(* Boolean->Leibniz *)openNamegenletcompute_bl_goalenvhandle(ind,u)lnamesparrecnparrec=letlist_id=list_idlnamesparrecinleteqI=eqIhandle(ind,u)list_idinletavoid=avoid_of_list_idlist_idinletx=next_ident_away(Id.of_string"x")avoidinlety=next_ident_away(Id.of_string"y")(Id.Set.addxavoid)inletopenTerminletcreate_inputc=letbl_typ=List.map(fun(s,seq,_,_)->mkNamedProd(Context.make_annotxSorts.Relevant)(mkVars)(mkNamedProd(Context.make_annotySorts.Relevant)(mkVars)(mkArrow(mkApp(eq(),[|bb();mkApp(mkVarseq,[|mkVarx;mkVary|]);tt()|]))Sorts.Relevant(mkApp(eq(),[|mkVars;mkVarx;mkVary|])))))list_idinletbl_input=List.fold_left2(funa(s,_,sbl,_)b->mkNamedProd(Context.make_annotsblSorts.Relevant)ba)c(List.revlist_id)(List.revbl_typ)inleteqs_typ=List.map(fun(s,_,_,_)->mkProd(Context.make_annotAnonymousSorts.Relevant,mkVars,mkProd(Context.make_annotAnonymousSorts.Relevant,mkVars,(bb()))))list_idinleteq_input=List.fold_left2(funa(s,seq,_,_)b->mkNamedProd(Context.make_annotseqSorts.Relevant)ba)bl_input(List.revlist_id)(List.reveqs_typ)inList.fold_left(funadecl->letx=Context.map_annot(functionNames->s|Anonymous->next_ident_away(Id.of_string"A")avoid)(RelDecl.get_annotdecl)inmkNamedProdx(RelDecl.get_typedecl)a)eq_inputlnamesparrecincreate_input(mkNamedProd(Context.make_annotxSorts.Relevant)(mkFullIndenv(ind,u)(2*nparrec))(mkNamedProd(Context.make_annotySorts.Relevant)(mkFullIndenv(ind,u)(2*nparrec+1))(mkArrow(mkApp(eq(),[|bb();mkApp(eqI,[|mkVarx;mkVary|]);tt()|]))Sorts.Relevant(mkApp(eq(),[|mkFullIndenv(ind,u)(2*nparrec+3);mkVarx;mkVary|])))))letcompute_bl_tacthandleindlnamesparrecnparrec=letlist_id=list_idlnamesparrecinletfirst_intros=(List.map(fun(s,_,_,_)->s)list_id)@(List.map(fun(_,seq,_,_)->seq)list_id)@(List.map(fun(_,_,sbl,_)->sbl)list_id)inletopenTacticsinintros_using_thenfirst_introsbeginfunfresh_first_intros->Tacticals.tclTHENLIST[intro_using_then(Id.of_string"x")(funfreshn->induct_on(EConstr.mkVarfreshn));intro_using_then(Id.of_string"y")(funfreshm->destruct_on(EConstr.mkVarfreshm));intro_using_then(Id.of_string"Z")beginfunfreshz->Tacticals.tclTHENLIST[intros;Tacticals.tclTRY(Tacticals.tclORELSEreflexivitymy_discr_tac);simpl_in_hyp(freshz,Locus.InHyp);(*
repeat ( apply andb_prop in z;let z1:= fresh "Z" in destruct z as [z1 z]).
*)Tacticals.tclREPEAT(Tacticals.tclTHENLIST[Simple.apply_infreshz(EConstr.of_constr(andb_prop()));letopenTactypesindestruct_on_as(EConstr.mkVarfreshz)(IntroOrPattern[[CAst.make@@IntroNaming(IntroFresh(Id.of_string"Z"));CAst.make@@IntroNaming(IntroIdentifierfreshz)]])]);(*
Ci a1 ... an = Ci b1 ... bn
replace bi with ai; auto || replace bi with ai by apply typeofbi_prod ; auto
*)Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletconcl=Proofview.Goal.conclglinletsigma=Tacmach.projectglinmatchEConstr.kindsigmaconclwith|App(c,ca)->(matchEConstr.kindsigmacwith|Ind(indeq,u)->ifEnviron.QGlobRef.equalenv(GlobRef.IndRefindeq)Rocqlib.(lib_ref"core.eq.type")thenTacticals.tclTHEN(do_replace_blhandleind(List.revfresh_first_intros)nparrec(ca.(2))(ca.(1)))Auto.default_autoelseTacticals.tclZEROMSGPp.(str"Failure while solving Boolean->Leibniz.")|_->Tacticals.tclZEROMSGPp.(str" Failure while solving Boolean->Leibniz."))|_->Tacticals.tclZEROMSGPp.(str"Failure while solving Boolean->Leibniz.")end]end]endletmake_bl_schemeenvhandlemind=letmib=Environ.lookup_mindmindenvinifnot(Int.equal(Array.lengthmib.mind_packets)1)thenCErrors.user_errPp.(str"Automatic building of boolean->Leibniz lemmas not supported");(* Setting universes *)letauctx=Declareops.universes_contextmib.mind_universesinletu,uctx=UnivGen.fresh_instance_fromauctxNoneinletuctx=UState.merge_sort_context~sideff:falseUState.univ_rigid(UState.from_envenv)uctxinletind=(mind,0)inletnparrec=mib.mind_nparams_recinletlnonparrec,lnamesparrec=Inductive.inductive_nonrec_rec_paramdecls(mib,u)inletbl_goal=compute_bl_goalenvhandle(ind,u)lnamesparrecnparrecinletbl_goal=EConstr.of_constrbl_goalinletpoly=Declareops.inductive_is_polymorphicmibinletuctx=ifpolythenEvd.ustate(fst(Typing.sort_ofenv(Evd.from_ctxuctx)bl_goal))elseuctxinlet(ans,_,_,_,uctx)=Declare.build_by_tactic~polyenv~uctx~typ:bl_goal(compute_bl_tacthandle(ind,EConstr.EInstance.makeu)lnamesparrecnparrec)in([|ans|],uctx)letmake_bl_scheme_depsenvind=letinds=get_inductive_deps~noprop:falseenvindinletmapind=Ind_tables.SchemeMutualDep(ind,!bl_scheme_kind_aux())inInd_tables.SchemeMutualDep(ind,beq_scheme_kind)::List.mapmapindsletbl_scheme_kind=Ind_tables.declare_mutual_scheme_object"dec_bl"~deps:make_bl_scheme_depsmake_bl_schemelet_=bl_scheme_kind_aux:=fun()->bl_scheme_kind(**********************************************************************)(* Leibniz->Boolean *)letcompute_lb_goalenvhandle(ind,u)lnamesparrecnparrec=letlist_id=list_idlnamesparrecinleteq=eq()andtt=tt()andbb=bb()inletavoid=avoid_of_list_idlist_idinleteqI=eqIhandle(ind,u)list_idinletx=next_ident_away(Id.of_string"x")avoidinlety=next_ident_away(Id.of_string"y")(Id.Set.addxavoid)inletopenTerminletcreate_inputc=letlb_typ=List.map(fun(s,seq,_,_)->mkNamedProd(Context.make_annotxSorts.Relevant)(mkVars)(mkNamedProd(Context.make_annotySorts.Relevant)(mkVars)(mkArrow(mkApp(eq,[|mkVars;mkVarx;mkVary|]))Sorts.Relevant(mkApp(eq,[|bb;mkApp(mkVarseq,[|mkVarx;mkVary|]);tt|])))))list_idinletlb_input=List.fold_left2(funa(s,_,_,slb)b->mkNamedProd(Context.make_annotslbSorts.Relevant)ba)c(List.revlist_id)(List.revlb_typ)inleteqs_typ=List.map(fun(s,_,_,_)->mkProd(Context.make_annotAnonymousSorts.Relevant,mkVars,mkProd(Context.make_annotAnonymousSorts.Relevant,mkVars,bb)))list_idinleteq_input=List.fold_left2(funa(s,seq,_,_)b->mkNamedProd(Context.make_annotseqSorts.Relevant)ba)lb_input(List.revlist_id)(List.reveqs_typ)inList.fold_left(funadecl->letx=Context.map_annot(functionNames->s|Anonymous->Id.of_string"A")(RelDecl.get_annotdecl)inmkNamedProdx(RelDecl.get_typedecl)a)eq_inputlnamesparrecincreate_input(mkNamedProd(Context.make_annotxSorts.Relevant)(mkFullIndenv(ind,u)(2*nparrec))(mkNamedProd(Context.make_annotySorts.Relevant)(mkFullIndenv(ind,u)(2*nparrec+1))(mkArrow(mkApp(eq,[|mkFullIndenv(ind,u)(2*nparrec+2);mkVarx;mkVary|]))Sorts.Relevant(mkApp(eq,[|bb;mkApp(eqI,[|mkVarx;mkVary|]);tt|])))))letcompute_lb_tacthandleindlnamesparrecnparrec=letlist_id=list_idlnamesparrecinletfirst_intros=(List.map(fun(s,_,_,_)->s)list_id)@(List.map(fun(_,seq,_,_)->seq)list_id)@(List.map(fun(_,_,_,slb)->slb)list_id)inletopenTacticsinintros_using_thenfirst_introsbeginfunfresh_first_intros->Tacticals.tclTHENLIST[intro_using_then(Id.of_string"x")(funfreshn->induct_on(EConstr.mkVarfreshn));intro_using_then(Id.of_string"y")(funfreshm->destruct_on(EConstr.mkVarfreshm));intro_using_then(Id.of_string"Z")beginfunfreshz->Tacticals.tclTHENLIST[intros;Tacticals.tclTRY(Tacticals.tclORELSEreflexivitymy_discr_tac);my_inj_tacfreshz;intros;simpl_in_concl;Auto.default_auto;Tacticals.tclREPEAT(Tacticals.tclTHENLIST[apply(EConstr.of_constr(andb_true_intro()));simplest_split;Auto.default_auto]);Proofview.Goal.enterbeginfungls->letconcl=Proofview.Goal.conclglsinletsigma=Tacmach.projectglsin(* assume the goal to be eq (eq_type ...) = true *)matchEConstr.kindsigmaconclwith|App(c,ca)->(match(EConstr.kindsigmaca.(1))with|App(c',ca')->letn=Array.lengthca'indo_replace_lbhandle(List.revfresh_first_intros)nparrecca'.(n-2)ca'.(n-1)|_->Tacticals.tclZEROMSGPp.(str"Failure while solving Leibniz->Boolean."))|_->Tacticals.tclZEROMSGPp.(str"Failure while solving Leibniz->Boolean.")end]end]endletmake_lb_schemeenvhandlemind=letmib=Environ.lookup_mindmindenvinifnot(Int.equal(Array.lengthmib.mind_packets)1)thenCErrors.user_errPp.(str"Automatic building of Leibniz->boolean lemmas not supported");letind=(mind,0)in(* Setting universes *)letauctx=Declareops.universes_contextmib.mind_universesinletu,uctx=UnivGen.fresh_instance_fromauctxNoneinletuctx=UState.merge_sort_context~sideff:falseUState.univ_rigid(UState.from_envenv)uctxinletnparrec=mib.mind_nparams_recinletlnonparrec,lnamesparrec=Inductive.inductive_nonrec_rec_paramdecls(mib,u)inletlb_goal=compute_lb_goalenvhandle(ind,u)lnamesparrecnparrecinletlb_goal=EConstr.of_constrlb_goalinletpoly=Declareops.inductive_is_polymorphicmibinletuctx=ifpolythenEvd.ustate(fst(Typing.sort_ofenv(Evd.from_ctxuctx)lb_goal))elseuctxinlet(ans,_,_,_,ctx)=Declare.build_by_tactic~polyenv~uctx~typ:lb_goal(compute_lb_tacthandleindlnamesparrecnparrec)in([|ans|],ctx)letmake_lb_scheme_depsenvind=letinds=get_inductive_deps~noprop:falseenvindinletmapind=Ind_tables.SchemeMutualDep(ind,!lb_scheme_kind_aux())inInd_tables.SchemeMutualDep(ind,beq_scheme_kind)::List.mapmapindsletlb_scheme_kind=Ind_tables.declare_mutual_scheme_object"dec_lb"~deps:make_lb_scheme_depsmake_lb_schemelet_=lb_scheme_kind_aux:=fun()->lb_scheme_kind(**********************************************************************)(* Decidable equality *)letcheck_not_is_defined()=ifnot(Rocqlib.has_ref"core.not.type")thenraise(UndefinedCst"not")(* {n=m}+{n<>m} part *)letcompute_dec_goalenvindlnamesparrecnparrec=check_not_is_defined();leteq=eq()andtt=tt()andbb=bb()inletlist_id=list_idlnamesparrecinletavoid=avoid_of_list_idlist_idinletx=next_ident_away(Id.of_string"x")avoidinlety=next_ident_away(Id.of_string"y")(Id.Set.addxavoid)inletopenTerminletcreate_inputc=letlb_typ=List.map(fun(s,seq,_,_)->mkNamedProd(Context.make_annotxSorts.Relevant)(mkVars)(mkNamedProd(Context.make_annotySorts.Relevant)(mkVars)(mkArrow(mkApp(eq,[|mkVars;mkVarx;mkVary|]))Sorts.Relevant(mkApp(eq,[|bb;mkApp(mkVarseq,[|mkVarx;mkVary|]);tt|])))))list_idinletbl_typ=List.map(fun(s,seq,_,_)->mkNamedProd(Context.make_annotxSorts.Relevant)(mkVars)(mkNamedProd(Context.make_annotySorts.Relevant)(mkVars)(mkArrow(mkApp(eq,[|bb;mkApp(mkVarseq,[|mkVarx;mkVary|]);tt|]))Sorts.Relevant(mkApp(eq,[|mkVars;mkVarx;mkVary|])))))list_idinletlb_input=List.fold_left2(funa(s,_,_,slb)b->mkNamedProd(Context.make_annotslbSorts.Relevant)ba)c(List.revlist_id)(List.revlb_typ)inletbl_input=List.fold_left2(funa(s,_,sbl,_)b->mkNamedProd(Context.make_annotsblSorts.Relevant)ba)lb_input(List.revlist_id)(List.revbl_typ)inleteqs_typ=List.map(fun(s,_,_,_)->mkProd(Context.make_annotAnonymousSorts.Relevant,mkVars,mkProd(Context.make_annotAnonymousSorts.Relevant,mkVars,bb)))list_idinleteq_input=List.fold_left2(funa(s,seq,_,_)b->mkNamedProd(Context.make_annotseqSorts.Relevant)ba)bl_input(List.revlist_id)(List.reveqs_typ)inList.fold_left(funadecl->letx=Context.map_annot(functionNames->s|Anonymous->Id.of_string"A")(RelDecl.get_annotdecl)inmkNamedProdx(RelDecl.get_typedecl)a)eq_inputlnamesparrecinleteqnm=mkApp(eq,[|mkFullIndenvind(3*nparrec+2);mkVarx;mkVary|])increate_input(mkNamedProd(Context.make_annotxSorts.Relevant)(mkFullIndenvind(3*nparrec))(mkNamedProd(Context.make_annotySorts.Relevant)(mkFullIndenvind(3*nparrec+1))(mkApp(sumbool(),[|eqnm;mkApp(UnivGen.constr_of_monomorphic_global(Global.env())@@Rocqlib.lib_ref"core.not.type",[|eqnm|])|]))))letcompute_dec_tacthandle(ind,u)lnamesparrecnparrec=leteq=eq()andtt=tt()andff=ff()andbb=bb()inletlist_id=list_idlnamesparrecinlet_=get_schemehandlebeq_scheme_kindindin(* This is just an assertion? *)let_non_fresh_eqI=eqIhandle(ind,u)list_idinleteqtruex=mkApp(eq,[|bb;x;tt|])inleteqfalsex=mkApp(eq,[|bb;x;ff|])inletfirst_intros=(List.map(fun(s,_,_,_)->s)list_id)@(List.map(fun(_,seq,_,_)->seq)list_id)@(List.map(fun(_,_,sbl,_)->sbl)list_id)@(List.map(fun(_,_,_,slb)->slb)list_id)inletopenTacticsinletfresh_idsgl=fresh_id_in_env(Id.Set.empty)s(Proofview.Goal.envgl)inintros_using_thenfirst_introsbeginfunfresh_first_intros->leteqI=leta=Array.of_listfresh_first_introsinletn=List.lengthlist_idinassert(Int.equal(Array.lengtha)(4*n));letfresh_list_id=List.initn(funi->(Array.getai,Array.geta(i+n),Array.geta(i+2*n),Array.geta(i+3*n)))ineqIhandle(ind,u)fresh_list_idinintro_using_then(Id.of_string"x")beginfunfreshn->intro_using_then(Id.of_string"y")beginfunfreshm->Proofview.Goal.enterbeginfungl->letfreshH=fresh_id(Id.of_string"H")glinleteqbnm=mkApp(eqI,[|mkVarfreshn;mkVarfreshm|])inletarfresh=Array.of_listfresh_first_introsinletxargs=Array.subarfresh0(2*nparrec)inletc=get_schemehandlebl_scheme_kindindinletblI=mkConstU(c,u)inletc=get_schemehandlelb_scheme_kindindinletlbI=mkConstU(c,u)in(* univ polymorphic schemes may have extra constraints
from using univ monomorphic f_equal and the like *)letenv,sigma=Proofview.Goal.(envgl,sigmagl)inletsigma,_=Typing.type_ofenvsigma(EConstr.of_constrblI)inletsigma,_=Typing.type_ofenvsigma(EConstr.of_constrlbI)inTacticals.tclTHENLIST[Proofview.Unsafe.tclEVARSsigma;(*we do this so we don't have to prove the same goal twice *)assert_by(NamefreshH)(EConstr.of_constr(mkApp(sumbool(),[|eqtrueeqbnm;eqfalseeqbnm|])))(Tacticals.tclTHEN(destruct_on(EConstr.of_constreqbnm))Auto.default_auto);Proofview.Goal.enterbeginfungl->letfreshH2=fresh_id(Id.of_string"H")glinTacticals.tclTHENS(destruct_on_using(EConstr.mkVarfreshH)freshH2)[(* left *)Tacticals.tclTHENLIST[simplest_left;apply(EConstr.of_constr(mkApp(blI,Array.mapmkVarxargs)));Auto.default_auto];(*right *)Proofview.Goal.enterbeginfungl->letfreshH3=fresh_id(Id.of_string"H")glinTacticals.tclTHENLIST[simplest_right;unfold_constr(Rocqlib.lib_ref"core.not.type");intro;Equality.subst_all();assert_by(NamefreshH3)(EConstr.of_constr(mkApp(eq,[|bb;mkApp(eqI,[|mkVarfreshm;mkVarfreshm|]);tt|])))(Tacticals.tclTHENLIST[apply(EConstr.of_constr(mkApp(lbI,Array.mapmkVarxargs)));Auto.default_auto]);Equality.general_rewrite~where:(SomefreshH3)~l2r:trueLocus.AllOccurrences~freeze:true~dep:false~with_evars:true((EConstr.mkVarfreshH2),NoBindings);my_discr_tac]end]end]endendendendletmake_eq_decidabilityenvhandlemind=letmib=Environ.lookup_mindmindenvinifnot(Int.equal(Array.lengthmib.mind_packets)1)thenraiseDecidabilityMutualNotSupported;letind=(mind,0)inletnparrec=mib.mind_nparams_recin(* Setting universes *)letauctx=Declareops.universes_contextmib.mind_universesinletu,uctx=UnivGen.fresh_instance_fromauctxNoneinletuctx=UState.merge_sort_context~sideff:falseUState.univ_rigid(UState.from_envenv)uctxinletlnonparrec,lnamesparrec=Inductive.inductive_nonrec_rec_paramdecls(mib,u)inletdec_goal=EConstr.of_constr(compute_dec_goalenv(ind,u)lnamesparrecnparrec)inletpoly=Declareops.inductive_is_polymorphicmibinletuctx=ifpolythenEvd.ustate(fst(Typing.sort_ofenv(Evd.from_ctxuctx)dec_goal))elseuctxinlet(ans,_,_,_,ctx)=Declare.build_by_tactic~polyenv~uctx~typ:dec_goal(compute_dec_tacthandle(ind,u)lnamesparrecnparrec)in([|ans|],ctx)leteq_dec_scheme_kind=Ind_tables.declare_mutual_scheme_object"eq_dec"~deps:(fun_ind->[SchemeMutualDep(ind,beq_scheme_kind);SchemeMutualDep(ind,bl_scheme_kind);SchemeMutualDep(ind,lb_scheme_kind)])make_eq_decidability(* The eq_dec_scheme proofs depend on the equality and discr tactics
but the inj tactics, that comes with discr, depends on the
eq_dec_scheme... *)let_=Equality.set_eq_dec_scheme_kindeq_dec_scheme_kind