123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenNamesopenConstropenEConstropenTacmachopenTacticsopenTacticalsopenIndfun_common(* funind doesn't support univ poly *)openUnsafeMonomorphic(***********************************************)(* [revert_graph kn post_tac hid] transforme an hypothesis [hid] having type Ind(kn,num) t1 ... tn res
when [kn] denotes a graph block into
f_num t1... tn = res (by applying [f_complete] to the first type) before apply post_tac on the result
if the type of hypothesis has not this form or if we cannot find the completeness lemma then we do nothing
*)letrevert_graphknpost_tachid=Proofview.Goal.enter(fungl->letenv=Proofview.Goal.envglinletsigma=projectglinlettyp=pf_get_hyp_typhidglinmatchEConstr.kindsigmatypwith|App(i,args)whenisIndsigmai->let((kn',num)asind'),u=destIndsigmaiinifEnviron.QMutInd.equalenvknkn'then(* We have generated a graph hypothesis so that we must change it if we can *)letinfo=matchfind_Function_of_graphind'with|Someinfo->info|None->(* The graphs are mutually recursive but we cannot find one of them !*)CErrors.anomaly(Pp.str"Cannot retrieve infos about a mutual block.")in(* if we can find a completeness lemma for this function
then we can come back to the functional form. If not, we do nothing
*)matchinfo.completeness_lemmawith|None->tclIDTAC|Somef_complete->letf_args,res=Array.chop(Array.lengthargs-1)argsintclTHENLIST[generalize[applist(mkConstf_complete,Array.to_listf_args@[res.(0);mkVarhid])];clear[hid];Simple.introhid;post_tachid]elsetclIDTAC|_->tclIDTAC)(*
[functional_inversion hid fconst f_correct ] is the functional version of [inversion]
[hid] is the hypothesis to invert, [fconst] is the function to invert and [f_correct]
is the correctness lemma for [fconst].
The sketch is the following~:
\begin{enumerate}
\item Transforms the hypothesis [hid] such that its type is now $res\ =\ f\ t_1 \ldots t_n$
(fails if it is not possible)
\item replace [hid] with $R\_f t_1 \ldots t_n res$ using [f_correct]
\item apply [inversion] on [hid]
\item finally in each branch, replace each hypothesis [R\_f ..] by [f ...] using [f_complete] (whenever
such a lemma exists)
\end{enumerate}
*)letfunctional_inversionknhidfconstf_correct=Proofview.Goal.enter(fungl->letold_ids=List.fold_rightId.Set.add(pf_ids_of_hypsgl)Id.Set.emptyinletsigma=projectglinlettype_of_h=pf_get_hyp_typhidglinmatchEConstr.kindsigmatype_of_hwith|App(eq,args)whenEConstr.eq_constrsigmaeq(make_eq())->letpre_tac,f_args,res=match(EConstr.kindsigmaargs.(1),EConstr.kindsigmaargs.(2))with|App(f,f_args),_whenEConstr.eq_constrsigmaffconst->((funhid->intros_symmetry(Locusops.onHyphid)),f_args,args.(2))|_,App(f,f_args)whenEConstr.eq_constrsigmaffconst->((funhid->tclIDTAC),f_args,args.(1))|_->((funhid->tclFAILn1Pp.(mt())),[||],args.(2))intclTHENLIST[pre_tachid;generalize[applist(f_correct,Array.to_listf_args@[res;mkVarhid])];clear[hid];Simple.introhid;Inv.invInv.FullInversionNone(Tactypes.NamedHyp(CAst.makehid));Proofview.Goal.enter(fungl->letnew_ids=List.filter(funid->not(Id.Set.memidold_ids))(pf_ids_of_hypsgl)intclMAP(revert_graphknpre_tac)(hid::new_ids))]|_->tclFAILn1Pp.(mt()))letinvfunqhypf=letf=matchfwith|GlobRef.ConstReff->f|_->CErrors.user_errPp.(str"Not a function")inmatchfind_Function_infosfwith|None->CErrors.user_err(Pp.str"No graph found")|Somefinfos->(matchfinfos.correctness_lemmawith|None->CErrors.user_err(Pp.str"Cannot use equivalence with graph!")|Somef_correct->letf_correct=mkConstf_correctandkn=fstfinfos.graph_indinTactics.try_intros_until(funhid->functional_inversionknhid(mkConstf)f_correct)qhyp)letinvfunqhypf=letexceptionNoFunctioninmatchfwith|Somef->invfunqhypf|None->lettac_actionhidgl=letsigma=projectglinlethyp_typ=pf_get_hyp_typhidglinmatchEConstr.kindsigmahyp_typwith|App(eq,args)whenEConstr.eq_constrsigmaeq(make_eq())->(letf1,_=decompose_appsigmaargs.(1)intryifnot(isConstsigmaf1)thenraiseNoFunction;letfinfos=Option.get(find_Function_infos(fst(destConstsigmaf1)))inletf_correct=mkConst(Option.getfinfos.correctness_lemma)andkn=fstfinfos.graph_indinfunctional_inversionknhidf1f_correctwithNoFunction|Option.IsNone->letf2,_=decompose_appsigmaargs.(2)inifisConstsigmaf2thenmatchfind_Function_infos(fst(destConstsigmaf2))with|None->ifdo_observe()thenCErrors.user_err(Pp.str"No graph found for any side of equality")elseCErrors.user_errPp.(str"Cannot find inversion information for hypothesis "++Ppconstr.pr_idhid)|Somefinfos->(matchfinfos.correctness_lemmawith|None->ifdo_observe()thenCErrors.user_err(Pp.str"Cannot use equivalence with graph for any side of the \
equality")elseCErrors.user_errPp.(str"Cannot find inversion information for hypothesis "++Ppconstr.pr_idhid)|Somef_correct->letf_correct=mkConstf_correctandkn=fstfinfos.graph_indinfunctional_inversionknhidf2f_correct)else(* NoFunction *)CErrors.user_errPp.(str"Hypothesis "++Ppconstr.pr_idhid++str" must contain at least one Function"))|_->CErrors.user_errPp.(Ppconstr.pr_idhid++str" must be an equality ")intry_intros_until(tac_action%>Proofview.Goal.enter)qhyp