123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenNamesopenConstropenTermopsopenEConstropenInductiveopsopenHipatternopenTacmach.NewopenTacticals.NewopenClenvopenTacticstypebranch_args={branchnum:int;(* the branch number *)nassums:int;(* number of assumptions/letin to be introduced *)branchsign:boollist;(* the signature of the branch.
true=assumption, false=let-in *)branchnames:Tactypes.intro_patterns}typeelim_kind=Caseofbool|Elim(* Find the right elimination suffix corresponding to the sort of the goal *)(* c should be of type A1->.. An->B with B an inductive definition *)letgeneral_elim_then_usingmk_elimrec_flagallnamestacpredicate(ind,u,args)id=letopenPpinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletsort=Retyping.get_sort_family_ofenvsigma(Proofview.Goal.conclgl)inletsigma,elim=matchmk_elimwith|Casedep->letu=EInstance.kindsigmauinlet(sigma,r)=Indrec.build_case_analysis_schemeenvsigma(ind,u)depsortin(sigma,EConstr.of_constrr)|Elim->letgr=Indrec.lookup_eliminatorenvindsortinEvd.fresh_globalenvsigmagrinletindclause=mk_clenv_from_envenvsigmaNone(mkVarid,mkApp(mkIndU(ind,u),args))in(* applying elimination_scheme just a little modified *)letelimclause=mk_clenv_from_envenvsigmaNone(elim,Retyping.get_type_ofenvsigmaelim)inletindmv=matchEConstr.kindelimclause.evd(last_argelimclause.evdelimclause.templval.Evd.rebus)with|Metamv->mv|_->CErrors.anomaly(str"elimination.")inletpmv=letp,_=decompose_appelimclause.evdelimclause.templtyp.Evd.rebusinmatchEConstr.kindelimclause.evdpwith|Metap->p|_->letname_elim=matchEConstr.kindsigmaelimwith|Const_|Var_->str" "++Printer.pr_econstr_envenvsigmaelim|_->mt()inCErrors.user_err~hdr:"Tacticals.general_elim_then_using"(str"The elimination combinator "++name_elim++str" is unknown.")inletelimclause'=clenv_fchain~with_univs:falseindmvelimclauseindclauseinletbranchsigns=Tacticals.compute_constructor_signatures~rec_flag(ind,u)inletbrnames=Tacticals.compute_induction_namesfalsebranchsignsallnamesinletflags=Unification.elim_flags()inletelimclause'=matchpredicatewith|None->elimclause'|Somep->clenv_unify~flagsReduction.CONV(mkMetapmv)pelimclause'inletafter_taci=letba={branchsign=branchsigns.(i);branchnames=brnames.(i);nassums=List.lengthbranchsigns.(i);branchnum=i+1;}intacbainletbranchtacs=List.init(Array.lengthbranchsigns)after_tacinProofview.tclTHEN(Clenv.res_pf~flagselimclause')(Proofview.tclEXTEND[]tclIDTACbranchtacs)end(* computing the case/elim combinators *)letmake_elim_branch_assumptionsbahyps=letassums=tryList.rev(List.firstnba.nassumshyps)withFailure_->CErrors.anomaly(Pp.str"make_elim_branch_assumptions.")inassumsletelim_on_batacba=Proofview.Goal.enterbeginfungl->letbranches=make_elim_branch_assumptionsba(Proofview.Goal.hypsgl)intacbranchesendletelimination_thentacid=letopenDeclarationsinProofview.Goal.enterbeginfungl->let((ind,u),t)=pf_applyTacred.reduce_to_atomic_indgl(pf_get_type_ofgl(mkVarid))inlet_,args=decompose_app_vect(Proofview.Goal.sigmagl)tinletisrec,mkelim=match(Global.lookup_mind(fstind)).mind_recordwith|NotRecord->true,Elim|FakeRecord|PrimRecord_->false,Casetrueingeneral_elim_then_usingmkelimisrecNonetacNone(ind,u,args)idend(* Supposed to be called without as clause *)letintroElimAssumsThentacba=assert(ba.branchnames==[]);letintroElimAssums=tclDOba.nassumsintroin(tclTHENintroElimAssums(elim_on_batacba))(* Supposed to be called with a non-recursive scheme *)letintroCaseAssumsThenwith_evarstacba=letn1=List.lengthba.branchsigninletn2=List.lengthba.branchnamesinlet(l1,l2),l3=ifn1<n2thenList.chopn1ba.branchnames,[]else(ba.branchnames,[]),List.make(n1-n2)falseinletintroCaseAssums=tclTHEN(intro_patternswith_evarsl1)(intros_clearingl3)in(tclTHENintroCaseAssums(elim_on_ba(tacl2)ba))letcase_tacdepnamestacelimindc=lettac=introCaseAssumsThenfalse(* ApplyOn not supported by inversion *)tacingeneral_elim_then_using(Casedep)falsenamestac(Someelim)indc(* The following tactic Decompose repeatedly applies the
elimination(s) rule(s) of the types satisfying the predicate
``recognizer'' onto a certain hypothesis. For example :
Require Elim.
Require Le.
Goal (y:nat){x:nat | (le O x)/\(le x y)}->{x:nat | (le O x)}.
Intros y H.
Decompose [sig and] H;EAuto.
Qed.
Another example :
Goal (A,B,C:Prop)(A/\B/\C \/ B/\C \/ C/\A) -> C.
Intros A B C H; Decompose [and or] H; Assumption.
Qed.
*)letrecgeneral_decompose_on_hyprecognizer=ifOnHyprecognizer(general_decompose_auxrecognizer)(fun_->Proofview.tclUNIT())andgeneral_decompose_auxrecognizerid=elimination_then(introElimAssumsThen(funbas->tclTHEN(clear[id])(tclMAP(general_decompose_on_hyprecognizer)(ids_of_named_contextbas))))id(* We should add a COMPLETE to be sure that the created hypothesis
doesn't stay if no elimination is possible *)(* Best strategies but loss of compatibility *)lettmphyp_name=Id.of_string"_TmpHyp"letgeneral_decomposerecognizerc=Proofview.Goal.enterbeginfungl->lettypc=pf_get_type_ofglcintclTHENS(cuttypc)[intro_using_thentmphyp_name(funid->ifOnHyprecognizer(general_decompose_auxrecognizer)(funid->clear[id])id);exact_no_checkc]endlethead_inindltgl=letsigma=Tacmach.New.projectglintryletity,_=extract_mrectypesigmatinList.exists(funi->Ind.CanOrd.equal(fsti)(fstity))indlwithNot_found->falseletdecompose_thesecl=Proofview.Goal.enterbeginfungl->letindl=List.map(funx->x,Univ.Instance.empty)lingeneral_decompose(funenvsigma(_,t)->head_inindltgl)cendletdecompose_andc=general_decompose(funenvsigma(_,t)->is_recordenvsigmat)cletdecompose_orc=general_decompose(funenvsigma(_,t)->is_disjunctionenvsigmat)cleth_decomposelc=decompose_theseclleth_decompose_or=decompose_orleth_decompose_and=decompose_and