123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299(************************************************************************)(* * 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) *)(************************************************************************)openPpopenCErrorsopenUtilopenNamesopenTermopsopenEnvironopenConstropenContextopenEConstropenVarsopenNamegenopenEvdopenPrinteropenReductionopsopenInductiveopsopenTacmachopenTacticalsopenTacticsopenContext.Named.DeclarationmoduleNamedDecl=Context.Named.Declarationletno_inductive_inconstrenvsigmaconstr=(str"Cannot recognize an inductive predicate in "++pr_leconstr_envenvsigmaconstr++str"."++spc()++str"If there is one, may be the structure of the arity"++spc()++str"or of the type of constructors"++spc()++str"is hidden by constant definitions.")(* Inversion stored in lemmas *)(* ALGORITHM:
An inversion stored in a lemma is computed from a term-pattern, in
a signature, as follows:
Suppose we have an inductive relation, (I abar), in a signature Gamma:
Gamma |- (I abar)
Then we compute the free-variables of abar. Suppose that Gamma is
thinned out to only include these.
[We need technically to require that all free-variables of the
types of the free variables of abar are themselves free-variables
of abar. This needs to be checked, but it should not pose a
problem - it is hard to imagine cases where it would not hold.]
Now, we pose the goal:
(P:(Gamma)Prop)(Gamma)(I abar)->(P vars[Gamma]).
We execute the tactic:
REPEAT Intro THEN (OnLastHyp (Inv NONE false o outSOME))
This leaves us with some subgoals. All the assumptions after "P"
in these subgoals are new assumptions. I.e. if we have a subgoal,
P:(Gamma)Prop, Gamma, Hbar:Tbar |- (P ybar)
then the assumption we needed to have was
(Hbar:Tbar)(P ybar)
So we construct all the assumptions we need, and rebuild the goal
with these assumptions. Then, we can re-apply the same tactic as
above, but instead of stopping after the inversion, we just apply
the respective assumption in each subgoal.
*)(* returns the sub_signature of sign corresponding to those identifiers that
* are not global. *)(*
let get_local_sign sign =
let lid = ids_of_sign sign in
let globsign = Global.named_context() in
let add_local id res_sign =
if not (mem_sign globsign id) then
add_sign (lookup_sign id sign) res_sign
else
res_sign
in
List.fold_right add_local lid nil_sign
*)(* returns the identifier of lid that was the latest declared in sign.
* (i.e. is the identifier id of lid such that
* sign_length (sign_prefix id sign) > sign_length (sign_prefix id' sign) >
* for any id'<>id in lid).
* it returns both the pair (id,(sign_prefix id sign)) *)(*
let max_prefix_sign lid sign =
let rec max_rec (resid,prefix) = function
| [] -> (resid,prefix)
| (id::l) ->
let pre = sign_prefix id sign in
if sign_length pre > sign_length prefix then
max_rec (id,pre) l
else
max_rec (resid,prefix) l
in
match lid with
| [] -> nil_sign
| id::l -> snd (max_rec (id, sign_prefix id sign) l)
*)letrecadd_prods_signenvsigmat=matchEConstr.kindsigma(whd_allenvsigmat)with|Prod(na,c1,b)->letid=id_of_name_using_hdcharenvsigmatna.binder_nameinletb'=subst1(mkVarid)binadd_prods_sign(push_named(LocalAssum({nawithbinder_name=id},c1))env)sigmab'|LetIn(na,c1,t1,b)->letid=id_of_name_using_hdcharenvsigmatna.binder_nameinletb'=subst1(mkVarid)binadd_prods_sign(push_named(LocalDef({nawithbinder_name=id},c1,t1))env)sigmab'|_->(env,t)(* [dep_option] indicates whether the inversion lemma is dependent or not.
If it is dependent and I is of the form (x_bar:T_bar)(I t_bar) then
the stated goal will be (x_bar:T_bar)(H:(I t_bar))(P t_bar H)
where P:(x_bar:T_bar)(H:(I x_bar))[sort].
The generalisation of such a goal at the moment of the dependent case should
be easy.
If it is non dependent, then if [I]=(I t_bar) and (x_bar:T_bar) are the
variables occurring in [I], then the stated goal will be:
(x_bar:T_bar)(I t_bar)->(P x_bar)
where P: P:(x_bar:T_bar)[sort].
*)letcompute_first_inversion_schemeenvsigmaindsortdep_option=letindf,realargs=dest_ind_typeindinletallvars=vars_of_envenvinletp=next_ident_away(Id.of_string"P")allvarsinletpty,goal=ifdep_optionthenletpty=make_arityenvsigmatrueindfsortinletr=relevance_of_inductive_typeenvindinletgoal=mkProd(make_annotAnonymousr,mkAppliedIndind,applist(mkVarp,realargs@[mkRel1]))inpty,goalelseleti=mkAppliedIndindinletivars=Termops.global_vars_setenvsigmaiinletrevargs,ownsign=fold_named_context(funenvd(revargs,hyps)->letd=EConstr.of_named_decldinletid=NamedDecl.get_iddinifId.Set.memidivarsthen((mkVarid)::revargs,Context.Named.adddhyps)else(revargs,hyps))env~init:([],[])inletpty=it_mkNamedProd_or_LetInsigma(mkSortsort)ownsigninletgoal=mkArrowiERelevance.relevant(applist(mkVarp,List.revrevargs))in(pty,goal)inletnpty=nf_allenvsigmaptyinletextenv=push_named(LocalAssum(make_annotpERelevance.relevant,npty))envinextenv,goal(* [inversion_scheme sign I]
Given a local signature, [sign], and an instance of an inductive
relation, [I], inversion_scheme will prove the associated inversion
scheme on sort [sort]. Depending on the value of [dep_option] it will
build a dependent lemma or a non-dependent one *)letinversion_scheme~name~polyenvsigmatsortdep_optioninv_op=let(env,i)=add_prods_signenvsigmatinletind=tryfind_rectypeenvsigmaiwithNot_found->user_err(no_inductive_inconstrenvsigmai)inlet(invEnv,invGoal)=compute_first_inversion_schemeenvsigmaindsortdep_optioninassert(Id.Set.subset(Termops.global_vars_setenvsigmainvGoal)(ids_of_named_context_val(named_context_valinvEnv)));(*
user_err
(str"Computed inversion goal was not closed in initial signature.");
*)letpf=Proof.start~name~poly(Evd.from_ctx(evar_universe_contextsigma))[invEnv,invGoal]inletpf,_,()=Proof.run_tacticenv(tclTHENintro(onLastHypIdinv_op))pfinletpfterm=List.hd(Proof.partial_proofpf)inletglobal_named_context=Global.named_context_val()inletownSign=refbeginfold_named_context(funenvdsign->letd=EConstr.of_named_decldinifmem_named_context_val(NamedDecl.get_idd)global_named_contextthensignelseContext.Named.adddsign)invEnv~init:Context.Named.emptyendinletavoid=refId.Set.emptyinletProof.{sigma}=Proof.datapfinletsigma=Evd.minimize_universessigmainletrecfill_holesc=matchEConstr.kindsigmacwith|Evar(e,args)->leth=next_ident_away(Id.of_string"H")!avoidinletty,inst=Evarutil.generalize_evar_over_relssigma(e,args)inavoid:=Id.Set.addh!avoid;ownSign:=Context.Named.add(LocalAssum(make_annothERelevance.relevant,ty))!ownSign;applist(mkVarh,inst)|_->EConstr.mapsigmafill_holescinletc=fill_holespftermin(* warning: side-effect on ownSign *)letinvProof=it_mkNamedLambda_or_LetInsigmac!ownSignininvProof,sigmaletadd_inversion_lemma~polynameenvsigmatsortdepinv_op=letinvProof,sigma=inversion_scheme~name~polyenvsigmatsortdepinv_opinletcinfo=Declare.CInfo.make~name~typ:None()inletinfo=Declare.Info.make~poly~kind:Decls.(IsProofLemma)()inlet_:Names.GlobRef.t=Declare.declare_definition~cinfo~info~opaque:false~body:invProofsigmain()(* inv_op = Inv (derives de complete inv. lemma)
* inv_op = InvNoThining (derives de semi inversion lemma) *)letadd_inversion_lemma_exn~polynacomcomsortbooltac=letenv=Global.env()inletsigma=Evd.from_envenvinletc,uctx=Constrintern.interp_typeenvsigmacominletsigma=Evd.from_ctxuctxinletsigma,sort=Evd.fresh_sort_in_family~rigid:univ_rigidsigmacomsortinadd_inversion_lemma~polynaenvsigmacsortbooltac(* ================================= *)(* Applying a given inversion lemma *)(* ================================= *)letlemInvidc=Proofview.Goal.enterbeginfungls->letenv=Proofview.Goal.envglsinletclause=Clenv.mk_clenv_fromenv(projectgls)(c,pf_get_type_ofglsc)inletmv=letmvs=Clenv.clenv_argumentsclauseinifList.is_emptymvsthenCErrors.user_errPp.(hov0(pr_econstr_env(pf_envgls)(projectgls)c++spc()++str"does not refer to an inversion lemma."))elseList.lastmvsintryletclause=Clenv.clenv_instantiatemvclause(EConstr.mkVarid,Typing.type_of_variableenvid)inClenv.res_pfclause~flags:(Unification.elim_flags())~with_evars:falsewith|Failure_|UserError_->user_err(str"Cannot refine current goal with the lemma "++pr_leconstr_env(pf_envgls)(projectgls)c++str".")endletlemInv_genidc=try_intros_until(funid->lemInvidc)idletlemInvInidcids=Proofview.Goal.enterbeginfungl->lethyps=List.map(funid->pf_get_hypidgl)idsinletintros_replace_ids=letconcl=Proofview.Goal.conclglinletsigma=projectglinletnb_of_new_hyp=nb_prodsigmaconcl-List.lengthidsinifnb_of_new_hyp<1thenintros_replacingidselse(tclTHEN(tclDOnb_of_new_hypintro)(intros_replacingids))in((tclTHEN(tclTHEN(Generalize.bring_hypshyps)(lemInvidc))(intros_replace_ids)))endletlemInvIn_genidcl=try_intros_until(funid->lemInvInidcl)idletlemInv_clauseidc=function|[]->lemInv_genidc|l->lemInvIn_genidcl