~ubuntu-branches/ubuntu/wily/coq-doc/wily

« back to all changes in this revision

Viewing changes to tactics/leminv.ml

  • Committer: Bazaar Package Importer
  • Author(s): Stéphane Glondu, Stéphane Glondu, Samuel Mimram
  • Date: 2010-01-07 22:50:39 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100107225039-n3cq82589u0qt0s2
Tags: 8.2pl1-1
[ Stéphane Glondu ]
* New upstream release (Closes: #563669)
  - remove patches
* Packaging overhaul:
  - use git, advertise it in Vcs-* fields of debian/control
  - use debhelper 7 and dh with override
  - use source format 3.0 (quilt)
* debian/control:
  - set Maintainer to d-o-m, set Uploaders to Sam and myself
  - add Homepage field
  - bump Standards-Version to 3.8.3
* Register PDF documentation into doc-base
* Add debian/watch
* Update debian/copyright

[ Samuel Mimram ]
* Change coq-doc's description to mention that it provides documentation in
  pdf format, not postscript, closes: #543545.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(************************************************************************)
 
2
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
 
3
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
 
4
(*   \VV/  **************************************************************)
 
5
(*    //   *      This file is distributed under the terms of the       *)
 
6
(*         *       GNU Lesser General Public License Version 2.1        *)
 
7
(************************************************************************)
 
8
 
 
9
(* $Id: leminv.ml 11897 2009-02-09 19:28:02Z barras $ *)
 
10
 
 
11
open Pp
 
12
open Util
 
13
open Names
 
14
open Nameops
 
15
open Term
 
16
open Termops
 
17
open Sign
 
18
open Evd
 
19
open Printer
 
20
open Reductionops
 
21
open Declarations
 
22
open Entries
 
23
open Inductiveops
 
24
open Environ
 
25
open Tacmach
 
26
open Proof_trees
 
27
open Proof_type
 
28
open Pfedit
 
29
open Evar_refiner
 
30
open Clenv
 
31
open Declare
 
32
open Tacticals
 
33
open Tactics
 
34
open Inv
 
35
open Vernacexpr
 
36
open Safe_typing
 
37
open Decl_kinds
 
38
 
 
39
let not_work_message = "tactic fails to build the inversion lemma, may be because the predicate has arguments that depend on other arguments"
 
40
 
 
41
let no_inductive_inconstr env constr =
 
42
  (str "Cannot recognize an inductive predicate in " ++ 
 
43
     pr_lconstr_env env constr ++
 
44
     str "." ++ spc () ++ str "If there is one, may be the structure of the arity" ++
 
45
     spc () ++ str "or of the type of constructors" ++ spc () ++
 
46
     str "is hidden by constant definitions.")
 
47
 
 
48
(* Inversion stored in lemmas *)
 
49
 
 
50
(* ALGORITHM:
 
51
 
 
52
   An inversion stored in a lemma is computed from a term-pattern, in
 
53
   a signature, as follows:
 
54
 
 
55
   Suppose we have an inductive relation, (I abar), in a signature Gamma:
 
56
 
 
57
       Gamma |- (I abar)
 
58
 
 
59
   Then we compute the free-variables of abar.  Suppose that Gamma is
 
60
   thinned out to only include these.
 
61
 
 
62
   [We need technically to require that all free-variables of the
 
63
    types of the free variables of abar are themselves free-variables
 
64
    of abar.  This needs to be checked, but it should not pose a
 
65
    problem - it is hard to imagine cases where it would not hold.]
 
66
 
 
67
   Now, we pose the goal:
 
68
 
 
69
       (P:(Gamma)Prop)(Gamma)(I abar)->(P vars[Gamma]).
 
70
 
 
71
   We execute the tactic:
 
72
 
 
73
   REPEAT Intro THEN (OnLastHyp (Inv NONE false o outSOME))
 
74
 
 
75
   This leaves us with some subgoals.  All the assumptions after "P"
 
76
   in these subgoals are new assumptions.  I.e. if we have a subgoal,
 
77
 
 
78
       P:(Gamma)Prop, Gamma, Hbar:Tbar |- (P ybar)
 
79
 
 
80
   then the assumption we needed to have was
 
81
 
 
82
      (Hbar:Tbar)(P ybar)
 
83
 
 
84
   So we construct all the assumptions we need, and rebuild the goal
 
85
   with these assumptions.  Then, we can re-apply the same tactic as
 
86
   above, but instead of stopping after the inversion, we just apply
 
87
   the respective assumption in each subgoal.
 
88
 
 
89
 *)
 
90
 
 
91
let thin_ids env (hyps,vars) =
 
92
  fst
 
93
    (List.fold_left
 
94
       (fun ((ids,globs) as sofar) (id,c,a) ->
 
95
          if List.mem id globs then
 
96
            match c with
 
97
              | None -> (id::ids,(global_vars env a)@globs)
 
98
              | Some body ->
 
99
                  (id::ids,(global_vars env body)@(global_vars env a)@globs)
 
100
          else sofar)
 
101
       ([],vars) hyps)
 
102
 
 
103
(* returns the sub_signature of sign corresponding to those identifiers that
 
104
 * are not global. *)
 
105
(*
 
106
let get_local_sign sign =
 
107
  let lid = ids_of_sign sign in
 
108
  let globsign = Global.named_context() in
 
109
  let add_local id res_sign = 
 
110
    if not (mem_sign globsign id) then 
 
111
      add_sign (lookup_sign id sign) res_sign
 
112
    else 
 
113
      res_sign
 
114
  in 
 
115
  List.fold_right add_local lid nil_sign
 
116
*)
 
117
(* returs the identifier of lid that was the latest declared in sign.
 
118
 * (i.e. is the identifier id of lid such that 
 
119
 * sign_length (sign_prefix id sign) > sign_length (sign_prefix id' sign) >
 
120
 * for any id'<>id in lid).
 
121
 * it returns both the pair (id,(sign_prefix id sign)) *)
 
122
(*
 
123
let max_prefix_sign lid sign =
 
124
  let rec max_rec (resid,prefix) = function
 
125
    | [] -> (resid,prefix)
 
126
    | (id::l) -> 
 
127
        let pre = sign_prefix id sign in  
 
128
        if sign_length pre > sign_length prefix then 
 
129
          max_rec (id,pre) l
 
130
        else 
 
131
          max_rec (resid,prefix) l
 
132
  in
 
133
  match lid with 
 
134
    | [] -> nil_sign
 
135
    | id::l -> snd (max_rec (id, sign_prefix id sign) l)
 
136
*)
 
137
let rec add_prods_sign env sigma t =
 
138
  match kind_of_term (whd_betadeltaiota env sigma t) with
 
139
    | Prod (na,c1,b) ->
 
140
        let id = id_of_name_using_hdchar env t na in
 
141
        let b'= subst1 (mkVar id) b in
 
142
        add_prods_sign (push_named (id,None,c1) env) sigma b'
 
143
    | LetIn (na,c1,t1,b) ->
 
144
        let id = id_of_name_using_hdchar env t na in
 
145
        let b'= subst1 (mkVar id) b in
 
146
        add_prods_sign (push_named (id,Some c1,t1) env) sigma b'
 
147
    | _ -> (env,t)
 
148
 
 
149
(* [dep_option] indicates wether the inversion lemma is dependent or not.
 
150
   If it is dependent and I is of the form (x_bar:T_bar)(I t_bar) then
 
151
   the stated goal will be (x_bar:T_bar)(H:(I t_bar))(P t_bar H) 
 
152
   where P:(x_bar:T_bar)(H:(I x_bar))[sort].
 
153
   The generalisation of such a goal at the moment of the dependent case should
 
154
   be easy.
 
155
 
 
156
   If it is non dependent, then if [I]=(I t_bar) and (x_bar:T_bar) are the
 
157
   variables occurring in [I], then the stated goal will be:
 
158
    (x_bar:T_bar)(I t_bar)->(P x_bar) 
 
159
   where P: P:(x_bar:T_bar)[sort].
 
160
*)
 
161
 
 
162
let compute_first_inversion_scheme env sigma ind sort dep_option =
 
163
  let indf,realargs = dest_ind_type ind in
 
164
  let allvars = ids_of_context env in
 
165
  let p = next_ident_away (id_of_string "P") allvars in
 
166
  let pty,goal =
 
167
    if dep_option  then
 
168
      let pty = make_arity env true indf sort in
 
169
      let goal = 
 
170
        mkProd
 
171
          (Anonymous, mkAppliedInd ind, applist(mkVar p,realargs@[mkRel 1]))
 
172
      in
 
173
      pty,goal
 
174
    else
 
175
      let i = mkAppliedInd ind in
 
176
      let ivars = global_vars env i in
 
177
      let revargs,ownsign =
 
178
        fold_named_context
 
179
          (fun env (id,_,_ as d) (revargs,hyps) ->
 
180
             if List.mem id ivars then 
 
181
               ((mkVar id)::revargs,add_named_decl d hyps)
 
182
             else 
 
183
               (revargs,hyps))
 
184
          env ~init:([],[]) 
 
185
      in
 
186
      let pty = it_mkNamedProd_or_LetIn (mkSort sort) ownsign in
 
187
      let goal = mkArrow i (applist(mkVar p, List.rev revargs)) in
 
188
      (pty,goal)
 
189
  in
 
190
  let npty = nf_betadeltaiota env sigma pty in
 
191
  let extenv = push_named (p,None,npty) env in
 
192
  extenv, goal
 
193
 
 
194
(* [inversion_scheme sign I]
 
195
 
 
196
   Given a local signature, [sign], and an instance of an inductive
 
197
   relation, [I], inversion_scheme will prove the associated inversion
 
198
   scheme on sort [sort]. Depending on the value of [dep_option] it will
 
199
   build a dependent lemma or a non-dependent one *)
 
200
 
 
201
let inversion_scheme env sigma t sort dep_option inv_op =
 
202
  let (env,i) = add_prods_sign env sigma t in
 
203
  let ind =
 
204
    try find_rectype env sigma i
 
205
    with Not_found ->
 
206
      errorlabstrm "inversion_scheme" (no_inductive_inconstr env i) 
 
207
  in
 
208
  let (invEnv,invGoal) =
 
209
    compute_first_inversion_scheme env sigma ind sort dep_option 
 
210
  in
 
211
  assert 
 
212
    (list_subset 
 
213
       (global_vars env invGoal) 
 
214
       (ids_of_named_context (named_context invEnv)));
 
215
  (*
 
216
    errorlabstrm "lemma_inversion"
 
217
    (str"Computed inversion goal was not closed in initial signature.");
 
218
  *)
 
219
  let invSign = named_context_val invEnv in
 
220
  let pfs = mk_pftreestate (mk_goal invSign invGoal None) in
 
221
  let pfs = solve_pftreestate (tclTHEN intro (onLastHyp inv_op)) pfs in
 
222
  let (pfterm,meta_types) = extract_open_pftreestate pfs in
 
223
  let global_named_context = Global.named_context () in
 
224
  let ownSign =
 
225
    fold_named_context
 
226
      (fun env (id,_,_ as d) sign ->
 
227
         if mem_named_context id global_named_context then sign
 
228
         else add_named_decl d sign)
 
229
      invEnv ~init:empty_named_context 
 
230
  in
 
231
  let (_,ownSign,mvb) =
 
232
    List.fold_left
 
233
      (fun (avoid,sign,mvb) (mv,mvty) ->
 
234
         let h = next_ident_away (id_of_string "H") avoid in
 
235
         (h::avoid, add_named_decl (h,None,mvty) sign, (mv,mkVar h)::mvb))
 
236
      (ids_of_context invEnv, ownSign, [])
 
237
      meta_types 
 
238
  in
 
239
  let invProof = 
 
240
    it_mkNamedLambda_or_LetIn
 
241
      (local_strong (fun _ -> whd_meta mvb) Evd.empty pfterm) ownSign 
 
242
  in
 
243
  invProof
 
244
 
 
245
let add_inversion_lemma name env sigma t sort dep inv_op =
 
246
  let invProof = inversion_scheme env sigma t sort dep inv_op in
 
247
  let _ = 
 
248
    declare_constant name
 
249
    (DefinitionEntry 
 
250
       { const_entry_body = invProof;
 
251
         const_entry_type = None;
 
252
         const_entry_opaque = false;
 
253
         const_entry_boxed = true && (Flags.boxed_definitions())}, 
 
254
     IsProof Lemma)
 
255
  in ()
 
256
 
 
257
(* open Pfedit *)
 
258
 
 
259
(* inv_op = Inv (derives de complete inv. lemma)
 
260
 * inv_op = InvNoThining (derives de semi inversion lemma) *)
 
261
 
 
262
let inversion_lemma_from_goal n na (loc,id) sort dep_option inv_op =
 
263
  let pts = get_pftreestate() in
 
264
  let gl = nth_goal_of_pftreestate n pts in
 
265
  let t = 
 
266
    try pf_get_hyp_typ gl id
 
267
    with Not_found -> Pretype_errors.error_var_not_found_loc loc id in
 
268
  let env = pf_env gl and sigma = project gl in
 
269
(* Pourquoi ??? 
 
270
  let fv = global_vars env t in
 
271
  let thin_ids = thin_ids (hyps,fv) in
 
272
  if not(list_subset thin_ids fv) then
 
273
    errorlabstrm "lemma_inversion"
 
274
      (str"Cannot compute lemma inversion when there are" ++ spc () ++
 
275
         str"free variables in the types of an inductive" ++ spc () ++
 
276
         str"which are not free in its instance."); *)
 
277
  add_inversion_lemma na env sigma t sort dep_option inv_op
 
278
   
 
279
let add_inversion_lemma_exn na com comsort bool tac =
 
280
  let env = Global.env () and sigma = Evd.empty in
 
281
  let c = Constrintern.interp_type sigma env com in
 
282
  let sort = Pretyping.interp_sort comsort in
 
283
  try
 
284
    add_inversion_lemma na env sigma c sort bool tac
 
285
  with 
 
286
    |   UserError ("Case analysis",s) -> (* r�f�rence � Indrec *)
 
287
          errorlabstrm "Inv needs Nodep Prop Set" s
 
288
 
 
289
(* ================================= *)
 
290
(* Applying a given inversion lemma  *)
 
291
(* ================================= *)
 
292
 
 
293
let lemInv id c gls =
 
294
  try
 
295
    let clause = mk_clenv_type_of gls c in
 
296
    let clause = clenv_constrain_last_binding (mkVar id) clause in
 
297
    Clenvtac.res_pf clause ~allow_K:true gls
 
298
  with 
 
299
    |  UserError (a,b) -> 
 
300
         errorlabstrm "LemInv" 
 
301
           (str "Cannot refine current goal with the lemma " ++ 
 
302
              pr_lconstr_env (Global.env()) c) 
 
303
 
 
304
let lemInv_gen id c = try_intros_until (fun id -> lemInv id c) id
 
305
 
 
306
let lemInvIn id c ids gls =
 
307
  let hyps = List.map (pf_get_hyp gls) ids in
 
308
  let intros_replace_ids gls =
 
309
    let nb_of_new_hyp  = nb_prod (pf_concl gls) - List.length ids in 
 
310
    if nb_of_new_hyp < 1  then 
 
311
      intros_replacing ids gls
 
312
    else 
 
313
      (tclTHEN (tclDO nb_of_new_hyp intro) (intros_replacing ids)) gls
 
314
  in 
 
315
  ((tclTHEN (tclTHEN (bring_hyps hyps) (lemInv id c))
 
316
    (intros_replace_ids)) gls)
 
317
 
 
318
let lemInvIn_gen id c l = try_intros_until (fun id -> lemInvIn id c l) id
 
319
 
 
320
let lemInv_clause id c = function
 
321
  | [] -> lemInv_gen id c
 
322
  | l -> lemInvIn_gen id c l