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

« back to all changes in this revision

Viewing changes to contrib/dp/dp.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
(* Authors: Nicolas Ayache and Jean-Christophe Filli�tre *)
 
2
(* Tactics to call decision procedures *)
 
3
 
 
4
(* Works in two steps: 
 
5
 
 
6
   - first the Coq context and the current goal are translated in
 
7
     Polymorphic First-Order Logic (see fol.mli in this directory)
 
8
 
 
9
   - then the resulting query is passed to the Why tool that translates
 
10
     it to the syntax of the selected prover (Simplify, CVC Lite, haRVey,
 
11
     Zenon)
 
12
*)
 
13
 
 
14
open Util
 
15
open Pp
 
16
open Libobject
 
17
open Summary
 
18
open Term
 
19
open Tacmach
 
20
open Tactics
 
21
open Tacticals
 
22
open Fol
 
23
open Names
 
24
open Nameops
 
25
open Termops
 
26
open Coqlib
 
27
open Hipattern
 
28
open Libnames
 
29
open Declarations
 
30
open Dp_why
 
31
 
 
32
let debug = ref false
 
33
let set_debug b = debug := b
 
34
let trace = ref false
 
35
let set_trace b = trace := b
 
36
let timeout = ref 10
 
37
let set_timeout n = timeout := n
 
38
 
 
39
let (dp_timeout_obj,_) = 
 
40
  declare_object 
 
41
    {(default_object "Dp_timeout") with  
 
42
       cache_function = (fun (_,x) -> set_timeout x);
 
43
       load_function = (fun _ (_,x) -> set_timeout x);
 
44
       export_function = (fun x -> Some x)}
 
45
 
 
46
let dp_timeout x = Lib.add_anonymous_leaf (dp_timeout_obj x)
 
47
 
 
48
let (dp_debug_obj,_) = 
 
49
  declare_object 
 
50
    {(default_object "Dp_debug") with  
 
51
       cache_function = (fun (_,x) -> set_debug x);
 
52
       load_function = (fun _ (_,x) -> set_debug x);
 
53
       export_function = (fun x -> Some x)}
 
54
 
 
55
let dp_debug x = Lib.add_anonymous_leaf (dp_debug_obj x)
 
56
 
 
57
let (dp_trace_obj,_) = 
 
58
  declare_object 
 
59
    {(default_object "Dp_trace") with  
 
60
       cache_function = (fun (_,x) -> set_trace x);
 
61
       load_function = (fun _ (_,x) -> set_trace x);
 
62
       export_function = (fun x -> Some x)}
 
63
 
 
64
let dp_trace x = Lib.add_anonymous_leaf (dp_trace_obj x)
 
65
 
 
66
let logic_dir = ["Coq";"Logic";"Decidable"]
 
67
let coq_modules =
 
68
  init_modules @ [logic_dir] @ arith_modules @ zarith_base_modules
 
69
    @ [["Coq"; "ZArith"; "BinInt"]]
 
70
    @ [["Coq"; "omega"; "OmegaLemmas"]]
 
71
 
 
72
let constant = gen_constant_in_modules "dp" coq_modules
 
73
 
 
74
let coq_Z = lazy (constant "Z")
 
75
let coq_Zplus = lazy (constant "Zplus")
 
76
let coq_Zmult = lazy (constant "Zmult")
 
77
let coq_Zopp = lazy (constant "Zopp")
 
78
let coq_Zminus = lazy (constant "Zminus")
 
79
let coq_Zdiv = lazy (constant "Zdiv")
 
80
let coq_Zs = lazy (constant "Zs")
 
81
let coq_Zgt = lazy (constant "Zgt")
 
82
let coq_Zle = lazy (constant "Zle")
 
83
let coq_Zge = lazy (constant "Zge")
 
84
let coq_Zlt = lazy (constant "Zlt")
 
85
let coq_Z0 = lazy (constant "Z0")
 
86
let coq_Zpos = lazy (constant "Zpos")
 
87
let coq_Zneg = lazy (constant "Zneg")
 
88
let coq_xH = lazy (constant "xH")
 
89
let coq_xI = lazy (constant "xI")
 
90
let coq_xO = lazy (constant "xO")
 
91
let coq_iff = lazy (constant "iff")
 
92
 
 
93
(* not Prop typed expressions *)
 
94
exception NotProp
 
95
 
 
96
(* not first-order expressions *)
 
97
exception NotFO
 
98
 
 
99
(* Renaming of Coq globals *)
 
100
 
 
101
let global_names = Hashtbl.create 97
 
102
let used_names = Hashtbl.create 97
 
103
 
 
104
let rename_global r =
 
105
  try 
 
106
    Hashtbl.find global_names r
 
107
  with Not_found ->
 
108
    let rec loop id = 
 
109
      if Hashtbl.mem used_names id then 
 
110
        loop (lift_ident id)
 
111
      else begin 
 
112
        Hashtbl.add used_names id ();
 
113
        let s = string_of_id id in
 
114
        Hashtbl.add global_names r s; 
 
115
        s
 
116
      end
 
117
    in
 
118
    loop (Nametab.id_of_global r)
 
119
 
 
120
let foralls =
 
121
  List.fold_right 
 
122
    (fun (x,t) p -> Forall (x, t, p))
 
123
 
 
124
let fresh_var = function
 
125
  | Anonymous -> rename_global (VarRef (id_of_string "x"))
 
126
  | Name x -> rename_global (VarRef x)
 
127
 
 
128
(* coq_rename_vars env [(x1,t1);...;(xn,tn)] renames the xi outside of 
 
129
   env names, and returns the new variables together with the new 
 
130
   environment *)
 
131
let coq_rename_vars env vars =
 
132
  let avoid = ref (ids_of_named_context (Environ.named_context env)) in
 
133
  List.fold_right
 
134
    (fun (na,t) (newvars, newenv) -> 
 
135
       let id = next_name_away na !avoid in
 
136
       avoid := id :: !avoid;
 
137
       id :: newvars, Environ.push_named (id, None, t) newenv)
 
138
    vars ([],env)
 
139
 
 
140
(* extract the prenex type quantifications i.e.
 
141
   type_quantifiers env (A1:Set)...(Ak:Set)t = A1...An, (env+Ai), t *)
 
142
let decomp_type_quantifiers env t =
 
143
  let rec loop vars t = match kind_of_term t with
 
144
    | Prod (n, a, t) when is_Set a || is_Type a -> 
 
145
        loop ((n,a) :: vars) t
 
146
    | _ -> 
 
147
        let vars, env = coq_rename_vars env vars in
 
148
        let t = substl (List.map mkVar vars) t in
 
149
        List.rev vars, env, t
 
150
  in
 
151
  loop [] t
 
152
 
 
153
(* same thing with lambda binders (for axiomatize body) *)
 
154
let decomp_type_lambdas env t =
 
155
  let rec loop vars t = match kind_of_term t with
 
156
    | Lambda (n, a, t) when is_Set a || is_Type a -> 
 
157
        loop ((n,a) :: vars) t
 
158
    | _ -> 
 
159
        let vars, env = coq_rename_vars env vars in
 
160
        let t = substl (List.map mkVar vars) t in
 
161
        List.rev vars, env, t
 
162
  in
 
163
  loop [] t
 
164
 
 
165
let decompose_arrows = 
 
166
  let rec arrows_rec l c = match kind_of_term c with
 
167
    | Prod (_,t,c) when not (dependent (mkRel 1) c) -> arrows_rec (t :: l) c
 
168
    | Cast (c,_,_) -> arrows_rec l c
 
169
    | _ -> List.rev l, c
 
170
  in 
 
171
  arrows_rec []
 
172
 
 
173
let rec eta_expanse t vars env i =
 
174
  assert (i >= 0);
 
175
  if i = 0 then
 
176
    t, vars, env
 
177
  else
 
178
    match kind_of_term (Typing.type_of env Evd.empty t) with
 
179
      | Prod (n, a, b) when not (dependent (mkRel 1) b) ->
 
180
          let avoid = ids_of_named_context (Environ.named_context env) in
 
181
          let id = next_name_away n avoid in
 
182
          let env' = Environ.push_named (id, None, a) env in
 
183
          let t' = mkApp (t, [| mkVar id |]) in
 
184
          eta_expanse t' (id :: vars) env' (pred i)
 
185
      | _ -> 
 
186
          assert false
 
187
 
 
188
let rec skip_k_args k cl = match k, cl with
 
189
  | 0, _ -> cl
 
190
  | _, _ :: cl -> skip_k_args (k-1) cl
 
191
  | _, [] -> raise NotFO
 
192
 
 
193
(* Coq global references *)
 
194
 
 
195
type global = Gnot_fo | Gfo of Fol.decl
 
196
 
 
197
let globals = ref Refmap.empty
 
198
let globals_stack = ref []
 
199
 
 
200
(* synchronization *)
 
201
let () =
 
202
  Summary.declare_summary "Dp globals"
 
203
    { Summary.freeze_function = (fun () -> !globals, !globals_stack);
 
204
      Summary.unfreeze_function = 
 
205
        (fun (g,s) -> globals := g; globals_stack := s);
 
206
      Summary.init_function = (fun () -> ());
 
207
      Summary.survive_module = false;
 
208
      Summary.survive_section = false }
 
209
 
 
210
let add_global r d = globals := Refmap.add r d !globals
 
211
let mem_global r = Refmap.mem r !globals
 
212
let lookup_global r = match Refmap.find r !globals with
 
213
  | Gnot_fo -> raise NotFO
 
214
  | Gfo d -> d
 
215
 
 
216
let locals = Hashtbl.create 97
 
217
 
 
218
let lookup_local r =  match Hashtbl.find locals r with
 
219
  | Gnot_fo -> raise NotFO
 
220
  | Gfo d -> d
 
221
 
 
222
let iter_all_constructors i f =  
 
223
  let _, oib = Global.lookup_inductive i in
 
224
  Array.iteri
 
225
    (fun j tj -> f j (mkConstruct (i, j+1)))
 
226
    oib.mind_nf_lc
 
227
 
 
228
 
 
229
(* injection c [t1,...,tn] adds the injection axiom
 
230
     forall x1:t1,...,xn:tn,y1:t1,...,yn:tn. 
 
231
       c(x1,...,xn)=c(y1,...,yn) -> x1=y1 /\ ... /\ xn=yn *)
 
232
 
 
233
let injection c l =
 
234
  let i = ref 0 in
 
235
  let var s = incr i; id_of_string (s ^ string_of_int !i) in
 
236
  let xl = List.map (fun t -> rename_global (VarRef (var "x")), t) l in
 
237
  i := 0;
 
238
  let yl = List.map (fun t -> rename_global (VarRef (var "y")), t) l in
 
239
  let f = 
 
240
    List.fold_right2 
 
241
      (fun (x,_) (y,_) p -> And (Fatom (Eq (App (x,[]),App (y,[]))), p))
 
242
      xl yl True
 
243
  in
 
244
  let vars = List.map (fun (x,_) -> App(x,[])) in
 
245
  let f = Imp (Fatom (Eq (App (c, vars xl), App (c, vars yl))), f) in
 
246
  let foralls = List.fold_right (fun (x,t) p -> Forall (x, t, p)) in
 
247
  let f = foralls xl (foralls yl f) in
 
248
  let ax = Axiom ("injection_" ^ c, f) in
 
249
  globals_stack := ax :: !globals_stack
 
250
 
 
251
(* rec_names_for c [|n1;...;nk|] builds the list of constant names for 
 
252
   identifiers n1...nk with the same path as c, if they exist; otherwise
 
253
   raises Not_found *)
 
254
let rec_names_for c =
 
255
  let mp,dp,_ = Names.repr_con c in
 
256
  array_map_to_list
 
257
    (function 
 
258
       | Name id -> 
 
259
           let c' = Names.make_con mp dp (label_of_id id) in
 
260
           ignore (Global.lookup_constant c');
 
261
           msgnl (Printer.pr_constr (mkConst c'));
 
262
           c'
 
263
       | Anonymous ->
 
264
           raise Not_found)
 
265
 
 
266
(* abstraction tables *)
 
267
 
 
268
let term_abstractions = Hashtbl.create 97
 
269
 
 
270
let new_abstraction = 
 
271
  let r = ref 0 in fun () -> incr r; "abstraction_" ^ string_of_int !r
 
272
 
 
273
(* Arithmetic constants *)
 
274
 
 
275
exception NotArithConstant
 
276
 
 
277
(* translates a closed Coq term p:positive into a FOL term of type int *)
 
278
let rec tr_positive p = match kind_of_term p with
 
279
  | Term.Construct _ when p = Lazy.force coq_xH ->
 
280
      Cst 1
 
281
  | Term.App (f, [|a|]) when f = Lazy.force coq_xI ->
 
282
      Plus (Mult (Cst 2, tr_positive a), Cst 1)
 
283
  | Term.App (f, [|a|]) when f = Lazy.force coq_xO ->
 
284
      Mult (Cst 2, tr_positive a)
 
285
  | Term.Cast (p, _, _) ->
 
286
      tr_positive p
 
287
  | _ ->
 
288
      raise NotArithConstant
 
289
 
 
290
(* translates a closed Coq term t:Z into a FOL term of type int *)
 
291
let rec tr_arith_constant t = match kind_of_term t with
 
292
  | Term.Construct _ when t = Lazy.force coq_Z0 ->
 
293
      Cst 0
 
294
  | Term.App (f, [|a|]) when f = Lazy.force coq_Zpos ->
 
295
      tr_positive a
 
296
  | Term.App (f, [|a|]) when f = Lazy.force coq_Zneg ->
 
297
      Moins (Cst 0, tr_positive a)
 
298
  | Term.Cast (t, _, _) ->
 
299
      tr_arith_constant t
 
300
  | _ -> 
 
301
      raise NotArithConstant
 
302
 
 
303
(* translate a Coq term t:Set into a FOL type expression;
 
304
   tv = list of type variables *)
 
305
and tr_type tv env t =
 
306
  let t = Reductionops.nf_betadeltaiota env Evd.empty t in
 
307
  if t = Lazy.force coq_Z then 
 
308
    Tid ("int", [])
 
309
  else match kind_of_term t with
 
310
    | Var x when List.mem x tv ->
 
311
        Tvar (string_of_id x)
 
312
    | _ ->
 
313
        let f, cl = decompose_app t in
 
314
        begin try
 
315
          let r = global_of_constr f in
 
316
          match tr_global env r with
 
317
            | DeclType (id, k) -> 
 
318
                assert (k = List.length cl); (* since t:Set *)
 
319
                Tid (id, List.map (tr_type tv env) cl)
 
320
            | _ -> 
 
321
                raise NotFO
 
322
        with 
 
323
          | Not_found ->
 
324
              raise NotFO
 
325
          | NotFO -> 
 
326
              (* we need to abstract some part of (f cl) *)
 
327
              (*TODO*)
 
328
              raise NotFO
 
329
        end
 
330
 
 
331
and make_term_abstraction tv env c =
 
332
  let ty = Typing.type_of env Evd.empty c in
 
333
  let id = new_abstraction () in
 
334
  match tr_decl env id ty with
 
335
    | DeclFun (id,_,_,_) as d ->
 
336
        begin try
 
337
          Hashtbl.find term_abstractions c
 
338
        with Not_found ->
 
339
          Hashtbl.add term_abstractions c id;
 
340
          globals_stack := d :: !globals_stack;
 
341
          id
 
342
        end
 
343
    | _ ->
 
344
        raise NotFO
 
345
 
 
346
(* translate a Coq declaration id:ty in a FOL declaration, that is either
 
347
   - a type declaration : DeclType (id, n) where n:int is the type arity
 
348
   - a function declaration : DeclFun (id, tl, t) ; that includes constants
 
349
   - a predicate declaration : DeclPred (id, tl)
 
350
   - an axiom : Axiom (id, p)
 
351
 *)
 
352
and tr_decl env id ty =
 
353
  let tv, env, t = decomp_type_quantifiers env ty in
 
354
  if is_Set t || is_Type t then
 
355
    DeclType (id, List.length tv)
 
356
  else if is_Prop t then
 
357
    DeclPred (id, List.length tv, [])
 
358
  else 
 
359
    let s = Typing.type_of env Evd.empty t in
 
360
    if is_Prop s then
 
361
      Axiom (id, tr_formula tv [] env t)
 
362
    else
 
363
      let l, t = decompose_arrows t in
 
364
      let l = List.map (tr_type tv env) l in
 
365
      if is_Prop t then
 
366
        DeclPred(id, List.length tv, l)
 
367
      else 
 
368
        let s = Typing.type_of env Evd.empty t in
 
369
        if is_Set s || is_Type s then 
 
370
          DeclFun (id, List.length tv, l, tr_type tv env t)
 
371
        else 
 
372
          raise NotFO
 
373
 
 
374
(* tr_global(r) = tr_decl(id(r),typeof(r)) + a cache mechanism *)
 
375
and tr_global env r = match r with
 
376
  | VarRef id ->
 
377
      lookup_local id
 
378
  | r ->
 
379
      try
 
380
        lookup_global r
 
381
      with Not_found ->
 
382
        try
 
383
          let ty = Global.type_of_global r in
 
384
          let id = rename_global r in
 
385
          let d = tr_decl env id ty in
 
386
          (* r can be already declared if it is a constructor *)
 
387
          if not (mem_global r) then begin 
 
388
            add_global r (Gfo d);
 
389
            globals_stack := d :: !globals_stack
 
390
          end;
 
391
          begin try axiomatize_body env r id d with NotFO -> () end;
 
392
          d
 
393
        with NotFO ->
 
394
          add_global r Gnot_fo;
 
395
          raise NotFO
 
396
 
 
397
and axiomatize_body env r id d = match r with
 
398
  | VarRef _ -> 
 
399
      assert false
 
400
  | ConstRef c ->
 
401
      begin match (Global.lookup_constant c).const_body with
 
402
        | Some b ->
 
403
            let b = force b in
 
404
            let axioms =
 
405
              (match d with
 
406
                 | DeclPred (id, _, []) ->
 
407
                     let tv, env, b = decomp_type_lambdas env b in
 
408
                     let value = tr_formula tv [] env b in
 
409
                     [id, Iff (Fatom (Pred (id, [])), value)]
 
410
                 | DeclFun (id, _, [], _) ->
 
411
                     let tv, env, b = decomp_type_lambdas env b in
 
412
                     let value = tr_term tv [] env b in
 
413
                     [id, Fatom (Eq (Fol.App (id, []), value))]
 
414
                 | DeclFun (id, _, l, _) | DeclPred (id, _, l) ->
 
415
                     (*Format.eprintf "axiomatize_body %S@." id;*)
 
416
                     let b = match kind_of_term b with
 
417
                       (* a single recursive function *)
 
418
                       | Fix (_, (_,_,[|b|])) -> 
 
419
                           subst1 (mkConst c) b
 
420
                       (* mutually recursive functions *)
 
421
                       | Fix ((_,i), (names,_,bodies)) ->
 
422
                           (* we only deal with named functions *)
 
423
                           begin try
 
424
                             let l = rec_names_for c names in
 
425
                             substl (List.rev_map mkConst l) bodies.(i)
 
426
                           with Not_found ->
 
427
                             b
 
428
                           end
 
429
                       | _ -> 
 
430
                           b
 
431
                     in
 
432
                     let tv, env, b = decomp_type_lambdas env b in
 
433
                     let vars, t = decompose_lam b in
 
434
                     let n = List.length l in
 
435
                     let k = List.length vars in
 
436
                     assert (k <= n);
 
437
                     let vars, env = coq_rename_vars env vars in
 
438
                     let t = substl (List.map mkVar vars) t in
 
439
                     let t, vars, env = eta_expanse t vars env (n-k) in
 
440
                     let vars = List.rev vars in
 
441
                     let bv = vars in
 
442
                     let vars = List.map (fun x -> string_of_id x) vars in
 
443
                     let fol_var x = Fol.App (x, []) in
 
444
                     let fol_vars = List.map fol_var vars in
 
445
                     let vars = List.combine vars l in
 
446
                     begin match d with
 
447
                       | DeclFun (_, _, _, ty) ->
 
448
                           begin match kind_of_term t with
 
449
                             | Case (ci, _, e, br) ->
 
450
                                 equations_for_case env id vars tv bv ci e br
 
451
                             | _ -> 
 
452
                                 let t = tr_term tv bv env t in
 
453
                                 let ax = 
 
454
                                   add_proof (Fun_def (id, vars, ty, t))
 
455
                                 in
 
456
                                 let p = Fatom (Eq (App (id, fol_vars), t)) in
 
457
                                 [ax, foralls vars p]
 
458
                           end
 
459
                       | DeclPred _ ->
 
460
                           let value = tr_formula tv bv env t in
 
461
                           let p = Iff (Fatom (Pred (id, fol_vars)), value) in
 
462
                           [id, foralls vars p]
 
463
                       | _ ->
 
464
                           assert false
 
465
                     end
 
466
                 | DeclType _ ->
 
467
                     raise NotFO
 
468
                 | Axiom _ -> assert false)
 
469
            in
 
470
            let axioms = List.map (fun (id,ax) -> Axiom (id, ax)) axioms in
 
471
            globals_stack := axioms @ !globals_stack
 
472
        | None -> 
 
473
            () (* Coq axiom *)
 
474
      end
 
475
  | IndRef i ->
 
476
      iter_all_constructors i
 
477
        (fun _ c ->
 
478
           let rc = global_of_constr c in
 
479
           try
 
480
             begin match tr_global env rc with
 
481
               | DeclFun (_, _, [], _) -> ()
 
482
               | DeclFun (idc, _, al, _) -> injection idc al
 
483
               | _ -> ()
 
484
             end
 
485
           with NotFO ->
 
486
             ())
 
487
  | _ -> ()
 
488
 
 
489
and equations_for_case env id vars tv bv ci e br = match kind_of_term e with
 
490
  | Var x when List.exists (fun (y, _) -> string_of_id x = y) vars ->
 
491
      let eqs = ref [] in
 
492
      iter_all_constructors ci.ci_ind
 
493
        (fun j cj ->
 
494
           try
 
495
             let cjr = global_of_constr cj in
 
496
             begin match tr_global env cjr with
 
497
               | DeclFun (idc, _, l, _) ->
 
498
                   let b = br.(j) in
 
499
                   let rec_vars, b = decompose_lam b in
 
500
                   let rec_vars, env = coq_rename_vars env rec_vars in
 
501
                   let coq_rec_vars = List.map mkVar rec_vars in
 
502
                   let b = substl coq_rec_vars b in
 
503
                   let rec_vars = List.rev rec_vars in
 
504
                   let coq_rec_term = applist (cj, List.rev coq_rec_vars) in
 
505
                   let b = replace_vars [x, coq_rec_term] b in
 
506
                   let bv = bv @ rec_vars in
 
507
                   let rec_vars = List.map string_of_id rec_vars in
 
508
                   let fol_var x = Fol.App (x, []) in
 
509
                   let fol_rec_vars = List.map fol_var rec_vars in
 
510
                   let fol_rec_term = App (idc, fol_rec_vars) in
 
511
                   let rec_vars = List.combine rec_vars l in
 
512
                   let fol_vars = List.map fst vars in
 
513
                   let fol_vars = List.map fol_var fol_vars in
 
514
                   let fol_vars = List.map (fun y -> match y with
 
515
                                              | App (id, _) ->
 
516
                                                  if id = string_of_id x
 
517
                                                  then fol_rec_term
 
518
                                                  else y
 
519
                                              | _ -> y)
 
520
                                    fol_vars in
 
521
                   let vars = vars @ rec_vars in
 
522
                   let rec remove l e = match l with
 
523
                     | [] -> []
 
524
                     | (y, t)::l' -> if y = string_of_id e then l'
 
525
                       else (y, t)::(remove l' e) in
 
526
                   let vars = remove vars x in
 
527
                   let p = 
 
528
                     Fatom (Eq (App (id, fol_vars), 
 
529
                                tr_term tv bv env b))
 
530
                   in
 
531
                   eqs := (id ^ "_" ^ idc, foralls vars p) :: !eqs
 
532
               | _ -> 
 
533
                   assert false end
 
534
           with NotFO ->
 
535
             ());
 
536
      !eqs
 
537
  | _ ->
 
538
      raise NotFO
 
539
 
 
540
(* assumption: t:T:Set *)
 
541
and tr_term tv bv env t = match kind_of_term t with
 
542
  | Term.App (f, [|a;b|]) when f = Lazy.force coq_Zplus -> 
 
543
      Plus (tr_term tv bv env a, tr_term tv bv env b)
 
544
  | Term.App (f, [|a;b|]) when f = Lazy.force coq_Zminus -> 
 
545
      Moins (tr_term tv bv env a, tr_term tv bv env b)
 
546
  | Term.App (f, [|a;b|]) when f = Lazy.force coq_Zmult -> 
 
547
      Mult (tr_term tv bv env a, tr_term tv bv env b)
 
548
  | Term.App (f, [|a;b|]) when f = Lazy.force coq_Zdiv -> 
 
549
      Div (tr_term tv bv env a, tr_term tv bv env b)
 
550
  | Term.Var id when List.mem id bv ->
 
551
      App (string_of_id id, [])
 
552
  | _ ->
 
553
      try
 
554
        tr_arith_constant t
 
555
      with NotArithConstant ->
 
556
        let f, cl = decompose_app t in
 
557
        begin try
 
558
          let r = global_of_constr f in
 
559
          match tr_global env r with
 
560
            | DeclFun (s, k, _, _) -> 
 
561
                let cl = skip_k_args k cl in
 
562
                Fol.App (s, List.map (tr_term tv bv env) cl)
 
563
            | _ -> 
 
564
                raise NotFO
 
565
        with 
 
566
          | Not_found ->
 
567
              raise NotFO
 
568
          | NotFO -> (* we need to abstract some part of (f cl) *)
 
569
              let rec abstract app = function
 
570
                | [] ->
 
571
                    Fol.App (make_term_abstraction tv env app, [])
 
572
                | x :: l as args ->
 
573
                    begin try
 
574
                      let s = make_term_abstraction tv env app in
 
575
                      Fol.App (s, List.map (tr_term tv bv env) args)
 
576
                    with NotFO ->
 
577
                      abstract (applist (app, [x])) l
 
578
                    end
 
579
              in
 
580
              let app,l = match cl with 
 
581
                | x :: l -> applist (f, [x]), l | [] -> raise NotFO
 
582
              in
 
583
              abstract app l
 
584
        end
 
585
 
 
586
and quantifiers n a b tv bv env =
 
587
  let vars, env = coq_rename_vars env [n,a] in
 
588
  let id = match vars with [x] -> x | _ -> assert false in
 
589
  let b = subst1 (mkVar id) b in
 
590
  let t = tr_type tv env a in
 
591
  let bv = id :: bv in
 
592
  id, t, bv, env, b
 
593
 
 
594
(* assumption: f is of type Prop *)
 
595
and tr_formula tv bv env f =
 
596
  let c, args = decompose_app f in
 
597
  match kind_of_term c, args with
 
598
    | Var id, [] -> 
 
599
        Fatom (Pred (rename_global (VarRef id), []))
 
600
    | _, [t;a;b] when c = build_coq_eq () ->
 
601
        let ty = Typing.type_of env Evd.empty t in
 
602
        if is_Set ty || is_Type ty then
 
603
          let _ = tr_type tv env t in
 
604
          Fatom (Eq (tr_term tv bv env a, tr_term tv bv env b))
 
605
        else 
 
606
          raise NotFO
 
607
    | _, [a;b] when c = Lazy.force coq_Zle ->
 
608
        Fatom (Le (tr_term tv bv env a, tr_term tv bv env b))
 
609
    | _, [a;b] when c = Lazy.force coq_Zlt ->
 
610
        Fatom (Lt (tr_term tv bv env a, tr_term tv bv env b))
 
611
    | _, [a;b] when c = Lazy.force coq_Zge ->
 
612
        Fatom (Ge (tr_term tv bv env a, tr_term tv bv env b))
 
613
    | _, [a;b] when c = Lazy.force coq_Zgt ->
 
614
        Fatom (Gt (tr_term tv bv env a, tr_term tv bv env b))
 
615
    | _, [] when c = build_coq_False () ->
 
616
        False
 
617
    | _, [] when c = build_coq_True () ->
 
618
        True
 
619
    | _, [a] when c = build_coq_not () ->
 
620
        Not (tr_formula tv bv env a)
 
621
    | _, [a;b] when c = build_coq_and () ->
 
622
        And (tr_formula tv bv env a, tr_formula tv bv env b)
 
623
    | _, [a;b] when c = build_coq_or () ->
 
624
        Or (tr_formula tv bv env a, tr_formula tv bv env b)
 
625
    | _, [a;b] when c = Lazy.force coq_iff ->
 
626
        Iff (tr_formula tv bv env a, tr_formula tv bv env b)
 
627
    | Prod (n, a, b), _ ->
 
628
        if is_imp_term f then
 
629
          Imp (tr_formula tv bv env a, tr_formula tv bv env b)
 
630
        else
 
631
          let id, t, bv, env, b = quantifiers n a b tv bv env in
 
632
          Forall (string_of_id id, t, tr_formula tv bv env b)
 
633
    | _, [_; a] when c = build_coq_ex () ->
 
634
        begin match kind_of_term a with
 
635
          | Lambda(n, a, b) ->
 
636
              let id, t, bv, env, b = quantifiers n a b tv bv env in
 
637
              Exists (string_of_id id, t, tr_formula tv bv env b)
 
638
          | _ -> 
 
639
              (* unusual case of the shape (ex p) *)
 
640
              raise NotFO (* TODO: we could eta-expanse *)
 
641
        end
 
642
    | _ ->
 
643
        begin try
 
644
          let r = global_of_constr c in
 
645
          match tr_global env r with
 
646
            | DeclPred (s, k, _) -> 
 
647
                let args = skip_k_args k args in
 
648
                Fatom (Pred (s, List.map (tr_term tv bv env) args))
 
649
            | _ -> 
 
650
                raise NotFO
 
651
        with Not_found ->
 
652
          raise NotFO
 
653
        end
 
654
 
 
655
 
 
656
let tr_goal gl =
 
657
  Hashtbl.clear locals;
 
658
  let tr_one_hyp (id, ty) = 
 
659
    try
 
660
      let s = rename_global (VarRef id) in
 
661
      let d = tr_decl (pf_env gl) s ty in
 
662
      Hashtbl.add locals id (Gfo d);
 
663
      d
 
664
    with NotFO ->
 
665
      Hashtbl.add locals id Gnot_fo;
 
666
      raise NotFO
 
667
  in
 
668
  let hyps =
 
669
    List.fold_right 
 
670
      (fun h acc -> try tr_one_hyp h :: acc with NotFO -> acc)
 
671
      (pf_hyps_types gl) []
 
672
  in
 
673
  let c = tr_formula [] [] (pf_env gl) (pf_concl gl) in
 
674
  let hyps = List.rev_append !globals_stack (List.rev hyps) in
 
675
  hyps, c
 
676
 
 
677
 
 
678
type prover = Simplify | Ergo | Yices | CVCLite | Harvey | Zenon | Gwhy
 
679
 
 
680
let remove_files = List.iter (fun f -> try Sys.remove f with _ -> ())
 
681
 
 
682
let sprintf = Format.sprintf
 
683
 
 
684
let file_contents f =
 
685
  let buf = Buffer.create 1024 in
 
686
  try
 
687
    let c = open_in f in
 
688
    begin try 
 
689
      while true do 
 
690
        let s = input_line c in Buffer.add_string buf s; 
 
691
        Buffer.add_char buf '\n'
 
692
      done;
 
693
      assert false
 
694
    with End_of_file ->
 
695
      close_in c;
 
696
      Buffer.contents buf
 
697
    end
 
698
  with _ -> 
 
699
    sprintf "(cannot open %s)" f
 
700
 
 
701
let timeout_sys_command cmd =
 
702
  if !debug then Format.eprintf "command line: %s@." cmd;
 
703
  let out = Filename.temp_file "out" "" in
 
704
  let cmd = sprintf "cpulimit %d %s > %s 2>&1" !timeout cmd out in
 
705
  let ret = Sys.command cmd in
 
706
  if !debug then 
 
707
    Format.eprintf "Output file %s:@.%s@." out (file_contents out);
 
708
  ret, out
 
709
 
 
710
let timeout_or_failure c cmd out =
 
711
  if c = 152 then 
 
712
    Timeout 
 
713
  else
 
714
    Failure 
 
715
      (sprintf "command %s failed with output:\n%s " cmd (file_contents out))
 
716
 
 
717
let prelude_files = ref ([] : string list)
 
718
 
 
719
let set_prelude l = prelude_files := l
 
720
 
 
721
let (dp_prelude_obj,_) = 
 
722
  declare_object 
 
723
    {(default_object "Dp_prelude") with  
 
724
       cache_function = (fun (_,x) -> set_prelude x);
 
725
       load_function = (fun _ (_,x) -> set_prelude x);
 
726
       export_function = (fun x -> Some x)}
 
727
 
 
728
let dp_prelude x = Lib.add_anonymous_leaf (dp_prelude_obj x)
 
729
 
 
730
let why_files f = String.concat " " (!prelude_files @ [f])
 
731
 
 
732
let call_simplify fwhy =
 
733
  let cmd = 
 
734
    sprintf "why --no-arrays --simplify --encoding sstrat %s" (why_files fwhy) 
 
735
  in
 
736
  if Sys.command cmd <> 0 then error ("call to " ^ cmd ^ " failed");
 
737
  let fsx = Filename.chop_suffix fwhy ".why" ^ "_why.sx" in
 
738
  let cmd = 
 
739
    sprintf "timeout %d Simplify %s > out 2>&1 && grep -q -w Valid out" 
 
740
      !timeout fsx
 
741
  in
 
742
  let out = Sys.command cmd in
 
743
  let r = 
 
744
    if out = 0 then Valid None else if out = 1 then Invalid else Timeout 
 
745
  in
 
746
  if not !debug then remove_files [fwhy; fsx];
 
747
  r
 
748
 
 
749
let call_ergo fwhy =
 
750
  let cmd = sprintf "why --no-arrays --why %s" (why_files fwhy) in
 
751
  if Sys.command cmd <> 0 then error ("call to " ^ cmd ^ " failed");
 
752
  let fwhy = Filename.chop_suffix fwhy ".why" ^ "_why.why" in
 
753
  let ftrace = Filename.temp_file "ergo_trace" "" in
 
754
  let cmd = 
 
755
    if !trace then
 
756
      sprintf "ergo -cctrace %s %s" ftrace fwhy
 
757
    else
 
758
      sprintf "ergo %s" fwhy
 
759
  in
 
760
  let ret,out = timeout_sys_command cmd in
 
761
  let r = 
 
762
    if ret <> 0 then 
 
763
      timeout_or_failure ret cmd out
 
764
    else if Sys.command (sprintf "grep -q -w Valid %s" out) = 0 then
 
765
      Valid (if !trace then Some ftrace else None)
 
766
    else if Sys.command (sprintf "grep -q -w \"I don't know\" %s" out) = 0 then
 
767
      DontKnow
 
768
    else if Sys.command (sprintf "grep -q -w \"Invalid\" %s" out) = 0 then
 
769
      Invalid
 
770
    else
 
771
      Failure ("command failed: " ^ cmd)
 
772
  in
 
773
  if not !debug then remove_files [fwhy; out];
 
774
  r
 
775
 
 
776
let call_zenon fwhy =
 
777
  let cmd = 
 
778
    sprintf "why --no-prelude --no-zenon-prelude --zenon %s" (why_files fwhy)
 
779
  in
 
780
  if Sys.command cmd <> 0 then error ("call to " ^ cmd ^ " failed");
 
781
  let fznn = Filename.chop_suffix fwhy ".why" ^ "_why.znn" in
 
782
  let out = Filename.temp_file "dp_out" "" in
 
783
  let cmd = 
 
784
    sprintf "timeout %d zenon -ocoqterm %s > %s 2>&1" !timeout fznn out 
 
785
  in
 
786
  let c = Sys.command cmd in
 
787
  if not !debug then remove_files [fwhy; fznn];
 
788
  if c = 137 then 
 
789
    Timeout
 
790
  else begin
 
791
    if c <> 0 then anomaly ("command failed: " ^ cmd);
 
792
    if Sys.command (sprintf "grep -q -w Error %s" out) = 0 then
 
793
      error "Zenon failed";
 
794
    let c = Sys.command (sprintf "grep -q PROOF-FOUND %s" out) in
 
795
    if c = 0 then Valid (Some out) else Invalid
 
796
  end
 
797
 
 
798
let call_yices fwhy =
 
799
  let cmd = 
 
800
    sprintf "why --no-arrays -smtlib --encoding sstrat %s" (why_files fwhy)
 
801
  in
 
802
  if Sys.command cmd <> 0 then error ("call to " ^ cmd ^ " failed");
 
803
  let fsmt = Filename.chop_suffix fwhy ".why" ^ "_why.smt" in
 
804
  let cmd = 
 
805
    sprintf "timeout %d yices -pc 0 -smt < %s > out 2>&1 && grep -q -w unsat out" 
 
806
      !timeout fsmt
 
807
  in
 
808
  let out = Sys.command cmd in
 
809
  let r = 
 
810
    if out = 0 then Valid None else if out = 1 then Invalid else Timeout 
 
811
  in
 
812
  if not !debug then remove_files [fwhy; fsmt];
 
813
  r
 
814
 
 
815
let call_cvcl fwhy =
 
816
  let cmd = 
 
817
    sprintf "why --no-arrays --cvcl --encoding sstrat %s" (why_files fwhy)
 
818
  in
 
819
  if Sys.command cmd <> 0 then error ("call to " ^ cmd ^ " failed");
 
820
  let fcvc = Filename.chop_suffix fwhy ".why" ^ "_why.cvc" in
 
821
  let cmd = 
 
822
    sprintf "timeout %d cvcl < %s > out 2>&1 && grep -q -w Valid out" 
 
823
      !timeout fcvc
 
824
  in
 
825
  let out = Sys.command cmd in
 
826
  let r = 
 
827
    if out = 0 then Valid None else if out = 1 then Invalid else Timeout 
 
828
  in
 
829
  if not !debug then remove_files [fwhy; fcvc];
 
830
  r
 
831
 
 
832
let call_harvey fwhy =
 
833
  let cmd = 
 
834
    sprintf "why --no-arrays --harvey --encoding strat %s" (why_files fwhy)
 
835
  in
 
836
  if Sys.command cmd <> 0 then error ("call to " ^ cmd ^ " failed");
 
837
  let frv = Filename.chop_suffix fwhy ".why" ^ "_why.rv" in
 
838
  let out = Sys.command (sprintf "rvc -e -t %s > /dev/null 2>&1" frv) in
 
839
  if out <> 0 then anomaly ("call to rvc -e -t " ^ frv ^ " failed");
 
840
  let f = Filename.chop_suffix frv ".rv" ^ "-0.baf" in
 
841
  let outf = Filename.temp_file "rv" ".out" in
 
842
  let out = 
 
843
    Sys.command (sprintf "timeout %d rv -e\"-T 2000\" %s > %s 2>&1" 
 
844
                   !timeout f outf) 
 
845
  in
 
846
  let r =
 
847
    if out <> 0 then 
 
848
      Timeout
 
849
    else
 
850
      let cmd = 
 
851
        sprintf "grep \"Proof obligation in\" %s | grep -q \"is valid\"" outf
 
852
      in
 
853
      if Sys.command cmd = 0 then Valid None else Invalid
 
854
  in
 
855
  if not !debug then remove_files [fwhy; frv; outf];
 
856
  r
 
857
 
 
858
let call_gwhy fwhy =
 
859
  let cmd = sprintf "gwhy --no-arrays  %s" (why_files fwhy) in
 
860
  if Sys.command cmd <> 0 then ignore (Sys.command (sprintf "emacs %s" fwhy));
 
861
  NoAnswer
 
862
 
 
863
let ergo_proof_from_file f gl =
 
864
  let s =
 
865
    let buf = Buffer.create 1024 in
 
866
    let c = open_in f in
 
867
    try
 
868
      while true do Buffer.add_string buf (input_line c) done; assert false
 
869
    with End_of_file ->
 
870
      close_in c;
 
871
      Buffer.contents buf
 
872
  in
 
873
  let parsed_constr = Pcoq.parse_string Pcoq.Constr.constr s in
 
874
  let t = Constrintern.interp_constr (project gl) (pf_env gl) parsed_constr in
 
875
  exact_check t gl
 
876
 
 
877
let call_prover prover q =
 
878
  let fwhy = Filename.temp_file "coq_dp" ".why" in
 
879
  Dp_why.output_file fwhy q;
 
880
  match prover with
 
881
    | Simplify -> call_simplify fwhy
 
882
    | Ergo -> call_ergo fwhy
 
883
    | Yices -> call_yices fwhy
 
884
    | Zenon -> call_zenon fwhy
 
885
    | CVCLite -> call_cvcl fwhy
 
886
    | Harvey -> call_harvey fwhy
 
887
    | Gwhy -> call_gwhy fwhy
 
888
  
 
889
let dp prover gl =
 
890
  Coqlib.check_required_library ["Coq";"ZArith";"ZArith"];
 
891
  let concl_type = pf_type_of gl (pf_concl gl) in
 
892
  if not (is_Prop concl_type) then error "Conclusion is not a Prop";
 
893
  try 
 
894
    let q = tr_goal gl in
 
895
    begin match call_prover prover q with
 
896
      | Valid (Some f) when prover = Zenon -> Dp_zenon.proof_from_file f gl
 
897
      | Valid (Some f) when prover = Ergo -> ergo_proof_from_file f gl
 
898
      | Valid _ -> Tactics.admit_as_an_axiom gl
 
899
      | Invalid -> error "Invalid"
 
900
      | DontKnow -> error "Don't know"
 
901
      | Timeout -> error "Timeout"
 
902
      | Failure s -> error s
 
903
      | NoAnswer -> Tacticals.tclIDTAC gl
 
904
    end
 
905
  with NotFO ->
 
906
    error "Not a first order goal"
 
907
      
 
908
 
 
909
let simplify = tclTHEN intros (dp Simplify)
 
910
let ergo = tclTHEN intros (dp Ergo)
 
911
let yices = tclTHEN intros (dp Yices)
 
912
let cvc_lite = tclTHEN intros (dp CVCLite)
 
913
let harvey = dp Harvey
 
914
let zenon = tclTHEN intros (dp Zenon)
 
915
let gwhy = tclTHEN intros (dp Gwhy)
 
916
 
 
917
let dp_hint l =
 
918
  let env = Global.env () in
 
919
  let one_hint (qid,r) = 
 
920
    if not (mem_global r) then begin
 
921
      let ty = Global.type_of_global r in
 
922
      let s = Typing.type_of env Evd.empty ty in
 
923
      if is_Prop s then
 
924
        try
 
925
          let id = rename_global r in
 
926
          let tv, env, ty = decomp_type_quantifiers env ty in
 
927
          let d = Axiom (id, tr_formula tv [] env ty) in
 
928
          add_global r (Gfo d);
 
929
          globals_stack := d :: !globals_stack
 
930
        with NotFO ->
 
931
          add_global r Gnot_fo;
 
932
          msg_warning
 
933
            (pr_reference qid ++ 
 
934
             str " ignored (not a first order proposition)")
 
935
        else begin
 
936
          add_global r Gnot_fo;
 
937
          msg_warning
 
938
            (pr_reference qid ++ str " ignored (not a proposition)")
 
939
        end
 
940
    end
 
941
  in
 
942
  List.iter one_hint (List.map (fun qid -> qid, Nametab.global qid) l)
 
943
 
 
944
let (dp_hint_obj,_) = 
 
945
  declare_object 
 
946
    {(default_object "Dp_hint") with  
 
947
       cache_function = (fun (_,l) -> dp_hint l);
 
948
       load_function = (fun _ (_,l) -> dp_hint l);
 
949
       export_function = (fun x -> Some x)}
 
950
 
 
951
let dp_hint l = Lib.add_anonymous_leaf (dp_hint_obj l)
 
952
 
 
953
let dp_predefined qid s =
 
954
  let r = Nametab.global qid in
 
955
  let ty = Global.type_of_global r in
 
956
  let env = Global.env () in
 
957
  let id = rename_global r in
 
958
  try
 
959
    let d = match tr_decl env id ty with
 
960
      | DeclType (_, n) -> DeclType (s, n)
 
961
      | DeclFun (_, n, tyl, ty) -> DeclFun (s, n, tyl, ty)
 
962
      | DeclPred (_, n, tyl) -> DeclPred (s, n, tyl) 
 
963
      | Axiom _ as d -> d
 
964
    in
 
965
    match d with
 
966
      | Axiom _ ->  msg_warning (str " ignored (axiom)")
 
967
      | d -> add_global r (Gfo d)
 
968
  with NotFO ->
 
969
    msg_warning (str " ignored (not a first order declaration)")
 
970
 
 
971
let (dp_predefined_obj,_) = 
 
972
  declare_object 
 
973
    {(default_object "Dp_predefined") with  
 
974
       cache_function = (fun (_,(id,s)) -> dp_predefined id s);
 
975
       load_function = (fun _ (_,(id,s)) -> dp_predefined id s);
 
976
       export_function = (fun x -> Some x)}
 
977
 
 
978
let dp_predefined id s = Lib.add_anonymous_leaf (dp_predefined_obj (id,s))
 
979
 
 
980
let _ = declare_summary "Dp options" 
 
981
          { freeze_function = 
 
982
              (fun () -> !debug, !trace, !timeout, !prelude_files);
 
983
            unfreeze_function = 
 
984
              (fun (d,tr,tm,pr) -> 
 
985
                debug := d; trace := tr; timeout := tm; prelude_files := pr);
 
986
            init_function = 
 
987
              (fun () -> 
 
988
                debug := false; trace := false; timeout := 10; 
 
989
                prelude_files := []);
 
990
            survive_module = true;
 
991
            survive_section = true }