]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_tactics/nnAuto.ml
Indexing local context for paramod.
[helm.git] / helm / software / components / ng_tactics / nnAuto.ml
1 (*
2     ||M||  This file is part of HELM, an Hypertextual, Electronic        
3     ||A||  Library of Mathematics, developed at the Computer Science     
4     ||T||  Department, University of Bologna, Italy.                     
5     ||I||                                                                 
6     ||T||  HELM is free software; you can redistribute it and/or         
7     ||A||  modify it under the terms of the GNU General Public License   
8     \   /  version 2 or (at your option) any later version.      
9      \ /   This software is distributed as is, NO WARRANTY.     
10       V_______________________________________________________________ *)
11
12 open Printf
13
14 let debug = ref false
15 let debug_print ?(depth=0) s = 
16   if !debug then prerr_endline (String.make depth '\t'^Lazy.force s) else ()
17 (* let print= debug_print *)
18  let print ?(depth=0) s = 
19   prerr_endline (String.make depth '\t'^Lazy.force s) 
20
21 let debug_do f = if !debug then f () else ()
22
23 open Continuationals.Stack
24 open NTacStatus
25 module Ast = CicNotationPt
26 let app_counter = ref 0
27
28 (* =================================== paramod =========================== *)
29 let auto_paramod ~params:(l,_) status goal =
30   let gty = get_goalty status goal in
31   let n,h,metasenv,subst,o = status#obj in
32   let status,t = term_of_cic_term status gty (ctx_of gty) in
33   let status, l = 
34     List.fold_left
35       (fun (status, l) t ->
36         let status, t = disambiguate status (ctx_of gty) t None in
37         let status, ty = typeof status (ctx_of t) t in
38         let status, t =  term_of_cic_term status t (ctx_of gty) in
39         let status, ty = term_of_cic_term status ty (ctx_of ty) in
40         (status, (t,ty) :: l))
41       (status,[]) l
42   in
43   match
44     NCicParamod.nparamod status metasenv subst (ctx_of gty) (NCic.Rel ~-1,t) l 
45   with
46   | [] -> raise (Error (lazy "no proof found",None))
47   | (pt, metasenv, subst)::_ -> 
48       let status = status#set_obj (n,h,metasenv,subst,o) in
49       instantiate status goal (mk_cic_term (ctx_of gty) pt)
50 ;;
51
52 let auto_paramod_tac ~params status = 
53   NTactics.distribute_tac (auto_paramod ~params) status
54 ;;
55
56 let fast_eq_check ~params status goal =
57   let gty = get_goalty status goal in
58   let n,h,metasenv,subst,o = status#obj in
59   let eq_cache = status#eq_cache in
60   let status,t = term_of_cic_term status gty (ctx_of gty) in 
61   match
62     NCicParamod.fast_eq_check status metasenv subst (ctx_of gty) 
63       eq_cache (NCic.Rel ~-1,t) 
64   with
65   | [] -> raise (Error (lazy "no proof found",None))
66   | (pt, metasenv, subst)::_ -> 
67       let status = status#set_obj (n,h,metasenv,subst,o) in
68       instantiate status goal (mk_cic_term (ctx_of gty) pt)
69 ;;
70
71 let fast_eq_check_tac  ~params = 
72   NTactics.distribute_tac (fast_eq_check ~params)
73 ;;
74
75 (*************** subsumption ****************)
76 module IntSet = Set.Make(struct type t = int let compare = compare end)
77 (* exceptions *)
78
79 let get_sgoalty status g =
80  let _,_,metasenv,subst,_ = status#obj in
81  try
82    let _, ctx, ty = NCicUtils.lookup_meta g metasenv in
83    let ty = NCicUntrusted.apply_subst subst ctx ty in
84    let ctx = NCicUntrusted.apply_subst_context 
85      ~fix_projections:true subst ctx
86    in
87      NTacStatus.mk_cic_term ctx ty
88  with NCicUtils.Meta_not_found _ as exn -> fail ~exn (lazy "get_sgoalty")
89 ;;
90
91 let deps status g =
92   let gty = get_sgoalty status g in
93   metas_of_term status gty
94 ;;
95
96 let menv_closure status gl = 
97   let rec closure acc = function
98     | [] -> acc
99     | x::l when IntSet.mem x acc -> closure acc l
100     | x::l -> closure (IntSet.add x acc) (deps status x @ l)
101   in closure IntSet.empty gl
102 ;;
103
104 let close_wrt_context =
105   List.fold_left 
106     (fun ty ctx_entry -> 
107         match ctx_entry with 
108        | name, NCic.Decl t -> NCic.Prod(name,t,ty)
109        | name, NCic.Def(bo, _) -> NCicSubstitution.subst bo ty)
110 ;;
111
112 let args_for_context ?(k=1) ctx =
113   let _,args =
114     List.fold_left 
115       (fun (n,l) ctx_entry -> 
116          match ctx_entry with 
117            | name, NCic.Decl t -> n+1,NCic.Rel(n)::l
118            | name, NCic.Def(bo, _) -> n+1,l)
119       (k,[]) ctx in
120     args
121
122 let constant_for_meta ctx ty i =
123   let name = "cic:/foo"^(string_of_int i)^".con" in
124   let uri = NUri.uri_of_string name in
125   let ty = close_wrt_context ty ctx in
126   (* prerr_endline (NCicPp.ppterm [] [] [] ty); *)
127   let attr = (`Generated,`Definition,`Local) in
128   let obj = NCic.Constant([],name,None,ty,attr) in
129     (* Constant  of relevance * string * term option * term * c_attr *)
130     (uri,0,[],[],obj)
131
132 (* not used *)
133 let refresh metasenv =
134   List.fold_left 
135     (fun (metasenv,subst) (i,(iattr,ctx,ty)) ->
136        let ikind = NCicUntrusted.kind_of_meta iattr in
137        let metasenv,j,instance,ty = 
138          NCicMetaSubst.mk_meta ~attrs:iattr 
139            metasenv ctx ~with_type:ty ikind in
140        let s_entry = i,(iattr, ctx, instance, ty) in
141        let metasenv = List.filter (fun x,_ -> i <> x) metasenv in
142          metasenv,s_entry::subst) 
143       (metasenv,[]) metasenv
144
145 (* close metasenv returns a ground instance of all the metas in the
146 metasenv, insantiatied with axioms, and the list of these axioms *)
147 let close_metasenv metasenv subst = 
148   (*
149   let metasenv = NCicUntrusted.apply_subst_metasenv subst metasenv in
150   *)
151   let metasenv = NCicUntrusted.sort_metasenv subst metasenv in 
152     List.fold_left 
153       (fun (subst,objs) (i,(iattr,ctx,ty)) ->
154          let ty = NCicUntrusted.apply_subst subst ctx ty in
155          let ctx = 
156            NCicUntrusted.apply_subst_context ~fix_projections:true 
157              subst ctx in
158          let (uri,_,_,_,obj) as okind = 
159            constant_for_meta ctx ty i in
160          try
161            NCicEnvironment.check_and_add_obj okind;
162            let iref = NReference.reference_of_spec uri NReference.Decl in
163            let iterm =
164              let args = args_for_context ctx in
165                if args = [] then NCic.Const iref 
166                else NCic.Appl(NCic.Const iref::args)
167            in
168            (* prerr_endline (NCicPp.ppterm ctx [] [] iterm); *)
169            let s_entry = i, ([], ctx, iterm, ty)
170            in s_entry::subst,okind::objs
171          with _ -> assert false)
172       (subst,[]) metasenv
173 ;;
174
175 let ground_instances status gl =
176   let _,_,metasenv,subst,_ = status#obj in
177   let subset = menv_closure status gl in
178   let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
179 (*
180   let submenv = metasenv in
181 *)
182   let subst, objs = close_metasenv submenv subst in
183   try
184     List.iter
185       (fun i -> 
186          let (_, ctx, t, _) = List.assoc i subst in
187            debug_print (lazy (NCicPp.ppterm ctx [] [] t));
188            List.iter 
189              (fun (uri,_,_,_,_) as obj -> 
190                 NCicEnvironment.invalidate_item (`Obj (uri, obj))) 
191              objs;
192            ())
193       gl
194   with
195       Not_found -> assert false 
196   (* (ctx,t) *)
197 ;;
198
199 let replace_meta i args target = 
200   let rec aux k = function
201     (* TODO: local context *)
202     | NCic.Meta (j,lc) when i = j ->
203         (match args with
204            | [] -> NCic.Rel 1
205            | _ -> let args = 
206                List.map (NCicSubstitution.subst_meta lc) args in
207                NCic.Appl(NCic.Rel k::args))
208     | NCic.Meta (j,lc) as m ->
209         (match lc with
210            _,NCic.Irl _ -> m
211          | n,NCic.Ctx l ->
212             NCic.Meta
213              (i,(0,NCic.Ctx
214                  (List.map (fun t ->
215                    aux k (NCicSubstitution.lift n t)) l))))
216     | t -> NCicUtils.map (fun _ k -> k+1) k aux t
217  in
218    aux 1 target
219 ;;
220
221 let close_wrt_metasenv subst =
222   List.fold_left 
223     (fun ty (i,(iattr,ctx,mty)) ->
224        let mty = NCicUntrusted.apply_subst subst ctx mty in
225        let ctx = 
226          NCicUntrusted.apply_subst_context ~fix_projections:true 
227            subst ctx in
228        let cty = close_wrt_context mty ctx in
229        let name = "foo"^(string_of_int i) in
230        let ty = NCicSubstitution.lift 1 ty in
231        let args = args_for_context ~k:1 ctx in
232          (* prerr_endline (NCicPp.ppterm ctx [] [] iterm); *)
233        let ty = replace_meta i args ty
234        in
235        NCic.Prod(name,cty,ty))
236 ;;
237
238 let close status g =
239   let _,_,metasenv,subst,_ = status#obj in
240   let subset = menv_closure status [g] in
241   let subset = IntSet.remove g subset in
242   let elems = IntSet.elements subset in 
243   let _, ctx, ty = NCicUtils.lookup_meta g metasenv in
244   let ty = NCicUntrusted.apply_subst subst ctx ty in
245   debug_print (lazy ("metas in " ^ (NCicPp.ppterm ctx [] metasenv ty)));
246   debug_print (lazy (String.concat ", " (List.map string_of_int elems)));
247   let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
248   let submenv = List.rev (NCicUntrusted.sort_metasenv subst submenv) in 
249 (*  
250     let submenv = metasenv in
251 *)
252   let ty = close_wrt_metasenv subst ty submenv in
253     debug_print (lazy (NCicPp.ppterm ctx [] [] ty));
254     ctx,ty
255 ;;
256
257
258
259 (* =================================== auto =========================== *)
260 (****************** AUTO ********************
261
262 let calculate_timeout flags = 
263     if flags.timeout = 0. then 
264       (debug_print (lazy "AUTO WITH NO TIMEOUT");
265        {flags with timeout = infinity})
266     else 
267       flags 
268 ;;
269 let is_equational_case goalty flags =
270   let ensure_equational t = 
271     if is_an_equational_goal t then true 
272     else false
273   in
274   (flags.use_paramod && is_an_equational_goal goalty) || 
275   (flags.use_only_paramod && ensure_equational goalty)
276 ;;
277
278 type menv = Cic.metasenv
279 type subst = Cic.substitution
280 type goal = ProofEngineTypes.goal * int * AutoTypes.sort
281 let candidate_no = ref 0;;
282 type candidate = int * Cic.term Lazy.t
283 type cache = AutoCache.cache
284
285 type fail = 
286   (* the goal (mainly for depth) and key of the goal *)
287   goal * AutoCache.cache_key
288 type op = 
289   (* goal has to be proved *)
290   | D of goal 
291   (* goal has to be cached as a success obtained using candidate as the first
292    * step *)
293   | S of goal * AutoCache.cache_key * candidate * int 
294 type elem = 
295   (* menv, subst, size, operations done (only S), operations to do, failures to cache if any op fails *)
296   menv * subst * int * op list * op list * fail list 
297 type status = 
298   (* list of computations that may lead to the solution: all op list will
299    * end with the same (S(g,_)) *)
300   elem list
301 type auto_result = 
302   (* menv, subst, alternatives, tables, cache *)
303   | Proved of menv * subst * elem list * AutomationCache.tables * cache 
304   | Gaveup of AutomationCache.tables * cache 
305
306
307 (* the status exported to the external observer *)  
308 type auto_status = 
309   (* context, (goal,candidate) list, and_list, history *)
310   Cic.context * (int * Cic.term * bool * int * (int * Cic.term Lazy.t) list) list * 
311   (int * Cic.term * int) list * Cic.term Lazy.t list
312
313 let d_prefix l =
314   let rec aux acc = function
315     | (D g)::tl -> aux (acc@[g]) tl
316     | _ -> acc
317   in
318     aux [] l
319 ;;
320
321 let calculate_goal_ty (goalno,_,_) s m = 
322   try
323     let _,cc,goalty = CicUtil.lookup_meta goalno m in
324     (* XXX applicare la subst al contesto? *)
325     Some (cc, CicMetaSubst.apply_subst s goalty)
326   with CicUtil.Meta_not_found i when i = goalno -> None
327 ;;
328
329 let calculate_closed_goal_ty (goalno,_,_) s = 
330   try
331     let cc,_,goalty = List.assoc goalno s in
332     (* XXX applicare la subst al contesto? *)
333     Some (cc, CicMetaSubst.apply_subst s goalty)
334   with Not_found -> 
335     None
336 ;;
337
338 let pp_status ctx status = 
339   if debug then 
340   let names = Utils.names_of_context ctx in
341   let pp x = 
342     let x = 
343       ProofEngineReduction.replace 
344         ~equality:(fun a b -> match b with Cic.Meta _ -> true | _ -> false) 
345           ~what:[Cic.Rel 1] ~with_what:[Cic.Implicit None] ~where:x
346     in
347     CicPp.pp x names
348   in
349   let string_of_do m s (gi,_,_ as g) d =
350     match calculate_goal_ty g s m with
351     | Some (_,gty) -> Printf.sprintf "D(%d, %s, %d)" gi (pp gty) d
352     | None -> Printf.sprintf "D(%d, _, %d)" gi d
353   in
354   let string_of_s m su k (ci,ct) gi =
355     Printf.sprintf "S(%d, %s, %s, %d)" gi (pp k) (pp (Lazy.force ct)) ci
356   in
357   let string_of_ol m su l =
358     String.concat " | " 
359       (List.map 
360         (function 
361           | D (g,d,s) -> string_of_do m su (g,d,s) d 
362           | S ((gi,_,_),k,c,_) -> string_of_s m su k c gi) 
363         l)
364   in
365   let string_of_fl m s fl = 
366     String.concat " | " 
367       (List.map (fun ((i,_,_),ty) -> 
368          Printf.sprintf "(%d, %s)" i (pp ty)) fl)
369   in
370   let rec aux = function
371     | [] -> ()
372     | (m,s,_,_,ol,fl)::tl ->
373         Printf.eprintf "< [%s] ;;; [%s]>\n" 
374           (string_of_ol m s ol) (string_of_fl m s fl);
375         aux tl
376   in
377     Printf.eprintf "-------------------------- status -------------------\n";
378     aux status;
379     Printf.eprintf "-----------------------------------------------------\n";
380 ;;
381   
382 let auto_status = ref [] ;;
383 let auto_context = ref [];;
384 let in_pause = ref false;;
385 let pause b = in_pause := b;;
386 let cond = Condition.create ();;
387 let mutex = Mutex.create ();;
388 let hint = ref None;;
389 let prune_hint = ref [];;
390
391 let step _ = Condition.signal cond;;
392 let give_hint n = hint := Some n;;
393 let give_prune_hint hint =
394   prune_hint := hint :: !prune_hint
395 ;;
396
397 let check_pause _ =
398   if !in_pause then
399     begin
400       Mutex.lock mutex;
401       Condition.wait cond mutex;
402       Mutex.unlock mutex
403     end
404 ;;
405
406 let get_auto_status _ = 
407   let status = !auto_status in
408   let and_list,elems,last = 
409     match status with
410     | [] -> [],[],[]
411     | (m,s,_,don,gl,fail)::tl ->
412         let and_list = 
413           HExtlib.filter_map 
414             (fun (id,d,_ as g) -> 
415               match calculate_goal_ty g s m with
416               | Some (_,x) -> Some (id,x,d) | None -> None)
417             (d_goals gl)
418         in
419         let rows = 
420           (* these are the S goalsin the or list *)
421           let orlist = 
422             List.map
423               (fun (m,s,_,don,gl,fail) -> 
424                 HExtlib.filter_map
425                   (function S (g,k,c,_) -> Some (g,k,c) | _ -> None) 
426                   (List.rev don @ gl))
427               status
428           in
429           (* this function eats id from a list l::[id,x] returning x, l *)
430           let eat_tail_if_eq id l = 
431             let rec aux (s, l) = function
432               | [] -> s, l
433               | ((id1,_,_),k1,c)::tl when id = id1 ->
434                   (match s with
435                   | None -> aux (Some c,l) tl
436                   | Some _ -> assert false)
437               | ((id1,_,_),k1,c as e)::tl -> aux (s, e::l) tl
438             in
439             let c, l = aux (None, []) l in
440             c, List.rev l
441           in
442           let eat_in_parallel id l =
443             let rec aux (b,eaten, new_l as acc) l =
444               match l with
445               | [] -> acc
446               | l::tl ->
447                   match eat_tail_if_eq id l with
448                   | None, l -> aux (b@[false], eaten, new_l@[l]) tl
449                   | Some t,l -> aux (b@[true],eaten@[t], new_l@[l]) tl
450             in
451             aux ([],[],[]) l
452           in
453           let rec eat_all rows l =
454             match l with
455             | [] -> rows
456             | elem::or_list ->
457                 match List.rev elem with
458                 | ((to_eat,depth,_),k,_)::next_lunch ->
459                     let b, eaten, l = eat_in_parallel to_eat l in
460                     let eaten = HExtlib.list_uniq eaten in
461                     let eaten = List.rev eaten in
462                     let b = true (* List.hd (List.rev b) *) in
463                     let rows = rows @ [to_eat,k,b,depth,eaten] in
464                     eat_all rows l
465                 | [] -> eat_all rows or_list
466           in
467           eat_all [] (List.rev orlist)
468         in
469         let history = 
470           HExtlib.filter_map
471             (function (S (_,_,(_,c),_)) -> Some c | _ -> None) 
472             gl 
473         in
474 (*         let rows = List.filter (fun (_,l) -> l <> []) rows in *)
475         and_list, rows, history
476   in
477   !auto_context, elems, and_list, last
478 ;;
479
480 (* Works if there is no dependency over proofs *)
481 let is_a_green_cut goalty =
482   CicUtil.is_meta_closed goalty
483 ;;
484 let rec first_s = function
485   | (D _)::tl -> first_s tl
486   | (S (g,k,c,s))::tl -> Some ((g,k,c,s),tl)
487   | [] -> None
488 ;;
489 let list_union l1 l2 =
490   (* TODO ottimizzare compare *)
491   HExtlib.list_uniq (List.sort compare (l1 @ l1))
492 ;;
493 let rec eq_todo l1 l2 =
494   match l1,l2 with
495   | (D g1) :: tl1,(D g2) :: tl2 when g1=g2 -> eq_todo tl1 tl2
496   | (S (g1,k1,(c1,lt1),i1)) :: tl1, (S (g2,k2,(c2,lt2),i2)) :: tl2
497     when i1 = i2 && g1 = g2 && k1 = k2 && c1 = c2 ->
498       if Lazy.force lt1 = Lazy.force lt2 then eq_todo tl1 tl2 else false
499   | [],[] -> true
500   | _ -> false
501 ;;
502 let eat_head todo id fl orlist = 
503   let rec aux acc = function
504   | [] -> [], acc
505   | (m, s, _, _, todo1, fl1)::tl as orlist -> 
506       let rec aux1 todo1 =
507         match first_s todo1 with
508         | None -> orlist, acc
509         | Some (((gno,_,_),_,_,_), todo11) ->
510             (* TODO confronto tra todo da ottimizzare *)
511             if gno = id && eq_todo todo11 todo then 
512               aux (list_union fl1 acc) tl
513             else 
514               aux1 todo11
515       in
516        aux1 todo1
517   in 
518     aux fl orlist
519 ;;
520 let close_proof p ty menv context = 
521   let metas =
522     List.map fst (CicUtil.metas_of_term p @ CicUtil.metas_of_term ty)
523   in
524   let menv = List.filter (fun (i,_,_) -> List.exists ((=)i) metas) menv in
525   naif_closure p menv context
526 ;;
527 (* XXX capire bene quando aggiungere alla cache *)
528 let add_to_cache_and_del_from_orlist_if_green_cut
529   g s m cache key todo orlist fl ctx size minsize
530
531   let cache = cache_remove_underinspection cache key in
532   (* prima per fare la irl usavamo il contesto vero e proprio e non quello 
533    * canonico! XXX *)
534   match calculate_closed_goal_ty g s with
535   | None -> assert false
536   | Some (canonical_ctx , gty) ->
537       let goalno,depth,sort = g in
538       let irl = mk_irl canonical_ctx in
539       let goal = Cic.Meta(goalno, irl) in
540       let proof = CicMetaSubst.apply_subst s goal in
541       let green_proof, closed_proof = 
542         let b = is_a_green_cut proof in
543         if not b then
544           b, (* close_proof proof gty m ctx *) proof 
545         else
546           b, proof
547       in
548       debug_print (lazy ("TENTATIVE CACHE: " ^ CicPp.ppterm key));
549       if is_a_green_cut key then
550         (* if the initia goal was closed, we cut alternatives *)
551         let _ = debug_print (lazy ("MANGIO: " ^ string_of_int goalno)) in
552         let orlist, fl = eat_head todo goalno fl orlist in
553         let cache = 
554           if size < minsize then 
555             (debug_print (lazy ("NO CACHE: 2 (size <= minsize)"));cache)
556           else 
557           (* if the proof is closed we cache it *)
558           if green_proof then cache_add_success cache key proof
559           else (* cache_add_success cache key closed_proof *) 
560             (debug_print (lazy ("NO CACHE: (no gree proof)"));cache)
561         in
562         cache, orlist, fl, true
563       else
564         let cache = 
565           debug_print (lazy ("TENTATIVE CACHE: " ^ CicPp.ppterm gty));
566           if size < minsize then 
567             (debug_print (lazy ("NO CACHE: (size <= minsize)")); cache) else
568           (* if the substituted goal and the proof are closed we cache it *)
569           if is_a_green_cut gty then
570             if green_proof then cache_add_success cache gty proof
571             else (* cache_add_success cache gty closed_proof *) 
572               (debug_print (lazy ("NO CACHE: (no green proof (gty))"));cache)
573           else (*
574             try
575               let ty, _ =
576                 CicTypeChecker.type_of_aux' ~subst:s 
577                   m ctx closed_proof CicUniv.oblivion_ugraph
578               in
579               if is_a_green_cut ty then 
580                 cache_add_success cache ty closed_proof
581               else cache
582             with
583             | CicTypeChecker.TypeCheckerFailure _ ->*) 
584           (debug_print (lazy ("NO CACHE: (no green gty )"));cache)
585         in
586         cache, orlist, fl, false
587 ;;
588 let close_failures (fl : fail list) (cache : cache) = 
589   List.fold_left 
590     (fun cache ((gno,depth,_),gty) -> 
591       if CicUtil.is_meta_closed gty then
592        ( debug_print (lazy ("FAIL: INDUCED: " ^ string_of_int gno));
593          cache_add_failure cache gty depth) 
594       else
595          cache)
596     cache fl
597 ;;
598 let put_in_subst subst metasenv  (goalno,_,_) canonical_ctx t ty =
599   let entry = goalno, (canonical_ctx, t,ty) in
600   assert_subst_are_disjoint subst [entry];
601   let subst = entry :: subst in
602   
603   let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
604
605   subst, metasenv
606 ;;
607
608 let mk_fake_proof metasenv subst (goalno,_,_) goalty context = 
609   None,metasenv,subst ,(lazy (Cic.Meta(goalno,mk_irl context))),goalty, [] 
610 ;;
611
612 let equational_case 
613   tables cache depth fake_proof goalno goalty subst context 
614     flags
615 =
616   let active,passive,bag = tables in
617   let ppterm = ppterm context in
618   let status = (fake_proof,goalno) in
619     if flags.use_only_paramod then
620       begin
621         debug_print (lazy ("PARAMODULATION SU: " ^ 
622                          string_of_int goalno ^ " " ^ ppterm goalty ));
623         let goal_steps, saturation_steps, timeout =
624           max_int,max_int,flags.timeout 
625         in
626         match
627           Saturation.given_clause bag status active passive 
628             goal_steps saturation_steps timeout
629         with 
630           | None, active, passive, bag -> 
631               [], (active,passive,bag), cache, flags
632           | Some(subst',(_,metasenv,_subst,proof,_, _),open_goals),active,
633             passive,bag ->
634               assert_subst_are_disjoint subst subst';
635               let subst = subst@subst' in
636               let open_goals = 
637                 order_new_goals metasenv subst open_goals ppterm 
638               in
639               let open_goals = 
640                 List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
641               in
642               incr candidate_no;
643               [(!candidate_no,proof),metasenv,subst,open_goals], 
644                 (active,passive,bag), cache, flags
645       end
646     else
647       begin
648         debug_print (lazy ("NARROWING DEL GOAL: " ^ 
649                          string_of_int goalno ^ " " ^ ppterm goalty ));
650         let goal_steps, saturation_steps, timeout =
651           1,0,flags.timeout 
652         in
653         match
654           Saturation.solve_narrowing bag status active passive goal_steps 
655         with 
656           | None, active, passive, bag -> 
657               [], (active,passive,bag), cache, flags
658           | Some(subst',(_,metasenv,_subst,proof,_, _),open_goals),active,
659             passive,bag ->
660               assert_subst_are_disjoint subst subst';
661               let subst = subst@subst' in
662               let open_goals = 
663                 order_new_goals metasenv subst open_goals ppterm 
664               in
665               let open_goals = 
666                 List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
667               in
668               incr candidate_no;
669               [(!candidate_no,proof),metasenv,subst,open_goals], 
670                 (active,passive,bag), cache, flags
671       end
672 (*
673       begin
674         let params = ([],["use_context","false"]) in
675         let automation_cache = { 
676               AutomationCache.tables = tables ;
677               AutomationCache.univ = Universe.empty; }
678         in
679         try 
680           let ((_,metasenv,subst,_,_,_),open_goals) =
681
682             solve_rewrite ~params ~automation_cache
683               (fake_proof, goalno)
684           in
685           let proof = lazy (Cic.Meta (-1,[])) in
686           [(!candidate_no,proof),metasenv,subst,[]],tables, cache, flags
687         with ProofEngineTypes.Fail _ -> [], tables, cache, flags
688 (*
689         let res = Saturation.all_subsumed bag status active passive in
690         let res' =
691           List.map 
692             (fun (subst',(_,metasenv,_subst,proof,_, _),open_goals) ->
693                assert_subst_are_disjoint subst subst';
694                let subst = subst@subst' in
695                let open_goals = 
696                  order_new_goals metasenv subst open_goals ppterm 
697                in
698                let open_goals = 
699                  List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
700                in
701                incr candidate_no;
702                  (!candidate_no,proof),metasenv,subst,open_goals)
703             res 
704           in
705           res', (active,passive,bag), cache, flags 
706 *)
707       end
708 *)
709 ;;
710
711 let sort_new_elems = 
712  List.sort (fun (_,_,_,l1) (_,_,_,l2) -> 
713          let p1 = List.length (prop_only l1) in 
714          let p2 = List.length (prop_only l2) in
715          if p1 = p2 then List.length l1 - List.length l2 else p1-p2)
716 ;;
717
718
719 let try_candidate dbd
720   goalty tables subst fake_proof goalno depth context cand 
721 =
722   let ppterm = ppterm context in
723   try 
724     let actives, passives, bag = tables in 
725     let (_,metasenv,subst,_,_,_), open_goals =
726        ProofEngineTypes.apply_tactic
727         (PrimitiveTactics.apply_tac ~term:cand)
728         (fake_proof,goalno) 
729     in
730     let tables = actives, passives, 
731       Equality.push_maxmeta bag 
732         (max (Equality.maxmeta bag) (CicMkImplicit.new_meta metasenv subst)) 
733     in
734     debug_print (lazy ("   OK: " ^ ppterm cand));
735     let metasenv = CicRefine.pack_coercion_metasenv metasenv in
736     let open_goals = order_new_goals metasenv subst open_goals ppterm in
737     let open_goals = List.map (fun (x,sort) -> x,depth-1,sort) open_goals in
738     incr candidate_no;
739     Some ((!candidate_no,lazy cand),metasenv,subst,open_goals), tables 
740   with 
741     | ProofEngineTypes.Fail s -> None,tables
742     | CicUnification.Uncertain s ->  None,tables
743 ;;
744
745 let applicative_case dbd
746   tables depth subst fake_proof goalno goalty metasenv context 
747   signature universe cache flags
748
749   (* let goalty_aux = 
750     match goalty with
751     | Cic.Appl (hd::tl) -> 
752         Cic.Appl (hd :: HExtlib.mk_list (Cic.Meta (0,[])) (List.length tl))
753     | _ -> goalty
754   in *)
755   let goalty_aux = goalty in
756   let candidates = 
757     get_candidates flags.skip_trie_filtering universe cache goalty_aux
758   in
759   (* if the goal is an equality we skip the congruence theorems 
760   let candidates =
761     if is_equational_case goalty flags 
762     then List.filter not_default_eq_term candidates 
763     else candidates 
764   in *)
765   let candidates = List.filter (only signature context metasenv) candidates 
766   in
767   let tables, elems = 
768     List.fold_left 
769       (fun (tables,elems) cand ->
770         match 
771           try_candidate dbd goalty
772             tables subst fake_proof goalno depth context cand
773         with
774         | None, tables -> tables, elems
775         | Some x, tables -> tables, x::elems)
776       (tables,[]) candidates
777   in
778   let elems = sort_new_elems elems in
779   elems, tables, cache
780 ;;
781
782 let try_smart_candidate dbd
783   goalty tables subst fake_proof goalno depth context cand 
784 =
785   let ppterm = ppterm context in
786   try
787     let params = ([],[]) in
788     let automation_cache = { 
789           AutomationCache.tables = tables ;
790           AutomationCache.univ = Universe.empty; }
791     in
792     debug_print (lazy ("candidato per " ^ string_of_int goalno 
793       ^ ": " ^ CicPp.ppterm cand));
794 (*
795     let (_,metasenv,subst,_,_,_) = fake_proof in
796     prerr_endline ("metasenv:\n" ^ CicMetaSubst.ppmetasenv [] metasenv);
797     prerr_endline ("subst:\n" ^ CicMetaSubst.ppsubst ~metasenv subst);
798 *)
799     let ((_,metasenv,subst,_,_,_),open_goals) =
800       apply_smart ~dbd ~term:cand ~params ~automation_cache
801         (fake_proof, goalno)
802     in
803     let metasenv = CicRefine.pack_coercion_metasenv metasenv in
804     let open_goals = order_new_goals metasenv subst open_goals ppterm in
805     let open_goals = List.map (fun (x,sort) -> x,depth-1,sort) open_goals in
806     incr candidate_no;
807     Some ((!candidate_no,lazy cand),metasenv,subst,open_goals), tables 
808   with 
809   | ProofEngineTypes.Fail s -> None,tables
810   | CicUnification.Uncertain s ->  None,tables
811 ;;
812
813 let smart_applicative_case dbd
814   tables depth subst fake_proof goalno goalty metasenv context signature
815   universe cache flags
816
817   let goalty_aux = 
818     match goalty with
819     | Cic.Appl (hd::tl) -> 
820         Cic.Appl (hd :: HExtlib.mk_list (Cic.Meta (0,[])) (List.length tl))
821     | _ -> goalty
822   in
823   let smart_candidates = 
824     get_candidates flags.skip_trie_filtering universe cache goalty_aux
825   in
826   let candidates = 
827     get_candidates flags.skip_trie_filtering universe cache goalty
828   in
829   let smart_candidates = 
830     List.filter
831       (fun x -> not(List.mem x candidates)) smart_candidates
832   in 
833   let debug_msg =
834     (lazy ("smart_candidates" ^ " = " ^ 
835              (String.concat "\n" (List.map CicPp.ppterm smart_candidates)))) in
836   debug_print debug_msg;
837   let candidates = List.filter (only signature context metasenv) candidates in
838   let smart_candidates = 
839     List.filter (only signature context metasenv) smart_candidates 
840   in
841 (*
842   let penalty cand depth = 
843     if only signature context metasenv cand then depth else ((prerr_endline (
844     "penalizzo " ^ CicPp.ppterm cand));depth -1)
845   in
846 *)
847   let tables, elems = 
848     List.fold_left 
849       (fun (tables,elems) cand ->
850         match 
851           try_candidate dbd goalty
852             tables subst fake_proof goalno depth context cand
853         with
854         | None, tables ->
855             (* if normal application fails we try to be smart *)
856             (match try_smart_candidate dbd goalty
857                tables subst fake_proof goalno depth context cand
858              with
859                | None, tables -> tables, elems
860                | Some x, tables -> tables, x::elems)
861         | Some x, tables -> tables, x::elems)
862       (tables,[]) candidates
863   in
864   let tables, smart_elems = 
865       List.fold_left 
866         (fun (tables,elems) cand ->
867           match 
868             try_smart_candidate dbd goalty
869               tables subst fake_proof goalno depth context cand
870           with
871           | None, tables -> tables, elems
872           | Some x, tables -> tables, x::elems)
873         (tables,[]) smart_candidates
874   in
875   let elems = sort_new_elems (elems @ smart_elems) in
876   elems, tables, cache
877 ;;
878
879 let equational_and_applicative_case dbd
880   signature universe flags m s g gty tables cache context 
881 =
882   let goalno, depth, sort = g in
883   let fake_proof = mk_fake_proof m s g gty context in
884   if is_equational_case gty flags then
885     let elems,tables,cache, flags =
886       equational_case tables cache
887         depth fake_proof goalno gty s context flags 
888     in
889     let more_elems, tables, cache =
890       if flags.use_only_paramod then
891         [],tables, cache
892       else
893         applicative_case dbd
894           tables depth s fake_proof goalno 
895             gty m context signature universe cache flags
896     in
897       elems@more_elems, tables, cache, flags            
898   else
899     let elems, tables, cache =
900       match LibraryObjects.eq_URI () with
901       | Some _ ->
902          smart_applicative_case dbd tables depth s fake_proof goalno 
903            gty m context signature universe cache flags
904       | None -> 
905          applicative_case dbd tables depth s fake_proof goalno 
906            gty m context signature universe cache flags
907     in
908       elems, tables, cache, flags  
909 ;;
910 let rec condition_for_hint i = function
911   | [] -> false
912   | S (_,_,(j,_),_):: tl -> j <> i (* && condition_for_hint i tl *)
913   | _::tl -> condition_for_hint i tl
914 ;;
915 let prunable_for_size flags s m todo =
916   let rec aux b = function
917     | (S _)::tl -> aux b tl
918     | (D (_,_,T))::tl -> aux b tl
919     | (D g)::tl -> 
920         (match calculate_goal_ty g s m with
921           | None -> aux b tl
922           | Some (canonical_ctx, gty) -> 
923             let gsize, _ = 
924               Utils.weight_of_term 
925                 ~consider_metas:false ~count_metas_occurrences:true gty in
926             let newb = b || gsize > flags.maxgoalsizefactor in
927             aux newb tl)
928     | [] -> b
929   in
930     aux false todo
931
932 (*
933 let prunable ty todo =
934   let rec aux b = function
935     | (S(_,k,_,_))::tl -> aux (b || Equality.meta_convertibility k ty) tl
936     | (D (_,_,T))::tl -> aux b tl
937     | D _::_ -> false
938     | [] -> b
939   in
940     aux false todo
941 ;;
942 *)
943
944 let prunable menv subst ty todo =
945   let rec aux = function
946     | (S(_,k,_,_))::tl ->
947          (match Equality.meta_convertibility_subst k ty menv with
948           | None -> aux tl
949           | Some variant -> 
950                no_progress variant tl (* || aux tl*))
951     | (D (_,_,T))::tl -> aux tl
952     | _ -> false
953   and no_progress variant = function
954     | [] -> (*prerr_endline "++++++++++++++++++++++++ no_progress";*) true
955     | D ((n,_,P) as g)::tl -> 
956         (match calculate_goal_ty g subst menv with
957            | None -> no_progress variant tl
958            | Some (_, gty) -> 
959                (match calculate_goal_ty g variant menv with
960                   | None -> assert false
961                   | Some (_, gty') ->
962                       if gty = gty' then no_progress variant tl
963 (* 
964 (prerr_endline (string_of_int n);
965  prerr_endline (CicPp.ppterm gty);
966  prerr_endline (CicPp.ppterm gty');
967  prerr_endline "---------- subst";
968  prerr_endline (CicMetaSubst.ppsubst ~metasenv:menv subst);
969  prerr_endline "---------- variant";
970  prerr_endline (CicMetaSubst.ppsubst ~metasenv:menv variant);
971  prerr_endline "---------- menv";
972  prerr_endline (CicMetaSubst.ppmetasenv [] menv); 
973                          no_progress variant tl) *)
974                       else false))
975     | _::tl -> no_progress variant tl
976   in
977     aux todo
978
979 ;;
980 let condition_for_prune_hint prune (m, s, size, don, todo, fl) =
981   let s = 
982     HExtlib.filter_map (function S (_,_,(c,_),_) -> Some c | _ -> None) todo 
983   in
984   List.for_all (fun i -> List.for_all (fun j -> i<>j) prune) s
985 ;;
986 let filter_prune_hint c l =
987   let prune = !prune_hint in
988   prune_hint := []; (* possible race... *)
989   if prune = [] then c,l
990   else 
991     cache_reset_underinspection c,      
992     List.filter (condition_for_prune_hint prune) l
993 ;;
994
995     
996
997 let
998   auto_all_solutions dbd tables universe cache context metasenv gl flags 
999 =
1000   let signature =
1001     List.fold_left 
1002       (fun set g ->
1003          MetadataConstraints.UriManagerSet.union set 
1004              (MetadataQuery.signature_of metasenv g)
1005        )
1006       MetadataConstraints.UriManagerSet.empty gl 
1007   in
1008   let goals = order_new_goals metasenv [] gl CicPp.ppterm in
1009   let goals = 
1010     List.map 
1011       (fun (x,s) -> D (x,flags.maxdepth,s)) goals 
1012   in
1013   let elems = [metasenv,[],1,[],goals,[]] in
1014   let rec aux tables solutions cache elems flags =
1015     match auto_main dbd tables context flags signature universe cache elems with
1016     | Gaveup (tables,cache) ->
1017         solutions,cache, tables
1018     | Proved (metasenv,subst,others,tables,cache) -> 
1019         if Unix.gettimeofday () > flags.timeout then
1020           ((subst,metasenv)::solutions), cache, tables
1021         else
1022           aux tables ((subst,metasenv)::solutions) cache others flags
1023   in
1024   let rc = aux tables [] cache elems flags in
1025     match rc with
1026     | [],cache,tables -> [],cache,tables
1027     | solutions, cache,tables -> 
1028         let solutions = 
1029           HExtlib.filter_map
1030             (fun (subst,newmetasenv) ->
1031               let opened = 
1032                 ProofEngineHelpers.compare_metasenvs ~oldmetasenv:metasenv ~newmetasenv
1033               in
1034               if opened = [] then Some subst else None)
1035             solutions
1036         in
1037          solutions,cache,tables
1038 ;;
1039
1040 (******************* AUTO ***************)
1041
1042
1043 let auto dbd flags metasenv tables universe cache context metasenv gl =
1044   let initial_time = Unix.gettimeofday() in  
1045   let signature =
1046     List.fold_left 
1047       (fun set g ->
1048          MetadataConstraints.UriManagerSet.union set 
1049              (MetadataQuery.signature_of metasenv g)
1050        )
1051       MetadataConstraints.UriManagerSet.empty gl 
1052   in
1053   let goals = order_new_goals metasenv [] gl CicPp.ppterm in
1054   let goals = List.map (fun (x,s) -> D(x,flags.maxdepth,s)) goals in
1055   let elems = [metasenv,[],1,[],goals,[]] in
1056   match auto_main dbd tables context flags signature universe cache elems with
1057   | Proved (metasenv,subst,_, tables,cache) -> 
1058       debug_print(lazy
1059         ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1060       Some (subst,metasenv), cache
1061   | Gaveup (tables,cache) -> 
1062       debug_print(lazy
1063         ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1064       None,cache
1065 ;;
1066
1067 let auto_tac ~(dbd:HSql.dbd) ~params:(univ,params) ~automation_cache (proof, goal) =
1068   let flags = flags_of_params params () in
1069   let use_library = flags.use_library in
1070   let universe, tables, cache =
1071     init_cache_and_tables 
1072      ~dbd ~use_library ~use_context:(not flags.skip_context)
1073      automation_cache univ (proof, goal) 
1074   in
1075   let _,metasenv,subst,_,_, _ = proof in
1076   let _,context,goalty = CicUtil.lookup_meta goal metasenv in
1077   let signature = MetadataQuery.signature_of metasenv goal in
1078   let signature = 
1079     List.fold_left 
1080       (fun set t ->
1081          let ty, _ = 
1082            CicTypeChecker.type_of_aux' metasenv context t 
1083              CicUniv.oblivion_ugraph
1084          in
1085          MetadataConstraints.UriManagerSet.union set 
1086            (MetadataConstraints.constants_of ty)
1087        )
1088       signature univ
1089   in
1090   let tables,cache =
1091     if flags.close_more then
1092       close_more 
1093         tables context (proof, goal) 
1094           (auto_all_solutions dbd) signature universe cache 
1095     else tables,cache in
1096   let initial_time = Unix.gettimeofday() in
1097   let (_,oldmetasenv,_,_,_, _) = proof in
1098     hint := None;
1099   let elem = 
1100     metasenv,subst,1,[],[D (goal,flags.maxdepth,P)],[]
1101   in
1102   match auto_main dbd tables context flags signature universe cache [elem] with
1103     | Proved (metasenv,subst,_, tables,cache) -> 
1104         debug_print (lazy 
1105           ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1106         let proof,metasenv =
1107         ProofEngineHelpers.subst_meta_and_metasenv_in_proof
1108           proof goal subst metasenv
1109         in
1110         let opened = 
1111           ProofEngineHelpers.compare_metasenvs ~oldmetasenv
1112             ~newmetasenv:metasenv
1113         in
1114           proof,opened
1115     | Gaveup (tables,cache) -> 
1116         debug_print
1117           (lazy ("TIME:"^
1118             string_of_float(Unix.gettimeofday()-.initial_time)));
1119         raise (ProofEngineTypes.Fail (lazy "Auto gave up"))
1120 ;;
1121 *)
1122
1123 (****************** types **************)
1124 type th_cache = (NCic.context * InvRelDiscriminationTree.t) list
1125
1126 let keys_of_term status t =
1127   let status, orig_ty = typeof status (ctx_of t) t in
1128   let _, ty, _ = saturate ~delta:max_int status orig_ty in
1129   let keys = [ty] in
1130   let keys = 
1131     let _, ty = term_of_cic_term status ty (ctx_of ty) in
1132     match ty with
1133     | NCic.Const (NReference.Ref (_,NReference.Def h)) 
1134     | NCic.Appl (NCic.Const(NReference.Ref(_,NReference.Def h))::_) 
1135        when h > 0 ->
1136          let _,ty,_= saturate status ~delta:(h-1) orig_ty in
1137          ty::keys
1138     | _ -> keys
1139   in
1140   status, keys
1141 ;;
1142
1143 let mk_th_cache status gl = 
1144   List.fold_left 
1145     (fun (status, acc) g ->
1146        let gty = get_goalty status g in
1147        let ctx = ctx_of gty in
1148        debug_print(lazy("th cache for: "^ppterm status gty));
1149        debug_print(lazy("th cache in: "^ppcontext status ctx));
1150        if List.mem_assq ctx acc then status, acc else
1151          let idx = InvRelDiscriminationTree.empty in
1152          let status,_,idx = 
1153            List.fold_left 
1154              (fun (status, i, idx) _ -> 
1155                 let t = mk_cic_term ctx (NCic.Rel i) in
1156                 debug_print(lazy("indexing: "^ppterm status t));
1157                 let status, keys = keys_of_term status t in
1158                 let idx =
1159                   List.fold_left (fun idx k -> 
1160                     InvRelDiscriminationTree.index idx k t) idx keys
1161                 in
1162                 status, i+1, idx)
1163              (status, 1, idx) ctx
1164           in
1165          status, (ctx, idx) :: acc)
1166     (status,[]) gl
1167 ;;
1168
1169 let add_to_th t c ty = 
1170   let key_c = ctx_of t in
1171   if not (List.mem_assq key_c c) then
1172       (key_c ,InvRelDiscriminationTree.index 
1173                InvRelDiscriminationTree.empty ty t ) :: c 
1174   else
1175     let rec replace = function
1176       | [] -> []
1177       | (x, idx) :: tl when x == key_c -> 
1178           (x, InvRelDiscriminationTree.index idx ty t) :: tl
1179       | x :: tl -> x :: replace tl
1180     in 
1181       replace c
1182 ;;
1183
1184 let pp_idx status idx =
1185    InvRelDiscriminationTree.iter idx
1186       (fun k set ->
1187          debug_print(lazy("K: " ^ NCicInverseRelIndexable.string_of_path k));
1188          Ncic_termSet.iter 
1189            (fun t -> debug_print(lazy("\t"^ppterm status t))) 
1190            set)
1191 ;;
1192
1193 let pp_th status = 
1194   List.iter 
1195     (fun ctx, idx ->
1196        debug_print(lazy( "-----------------------------------------------"));
1197        debug_print(lazy( (NCicPp.ppcontext ~metasenv:[] ~subst:[] ctx)));
1198        debug_print(lazy( "||====>  "));
1199        pp_idx status idx)
1200 ;;
1201
1202 let search_in_th gty th = 
1203   let c = ctx_of gty in
1204   let rec aux acc = function
1205    | [] -> Ncic_termSet.elements acc
1206    | (_::tl) as k ->
1207        try 
1208          let idx = List.assq k th in
1209          let acc = Ncic_termSet.union acc 
1210            (InvRelDiscriminationTree.retrieve_unifiables idx gty)
1211          in
1212          aux acc tl
1213        with Not_found -> aux acc tl
1214   in
1215     aux Ncic_termSet.empty c
1216 ;;
1217
1218 type flags = {
1219         do_types : bool; (* solve goals in Type *)
1220         maxwidth : int;
1221         maxsize  : int;
1222         maxdepth : int;
1223         timeout  : float;
1224 }
1225
1226 type sort = T | P
1227 type goal = int * sort (* goal, depth, sort *)
1228 type fail = goal * cic_term
1229 type candidate = int * Ast.term (* unique candidate number, candidate *)
1230
1231 exception Gaveup of IntSet.t (* a sublist of unprovable conjunctive
1232                                 atoms of the input goals *)
1233 exception Proved of #NTacStatus.tac_status
1234
1235 (* let close_failures _ c = c;; *)
1236 (* let prunable _ _ _ = false;; *)
1237 (* let cache_examine cache gty = `Notfound;; *)
1238 (* let put_in_subst s _ _ _  = s;; *)
1239 (* let add_to_cache_and_del_from_orlist_if_green_cut _ _ c _ _ o f _ = c, o, f, false ;; *)
1240 (* let cache_add_underinspection c _ _ = c;; *)
1241 let equational_case _ _ _ _ _ _ = [];;
1242 let only _ _ _ = true;; 
1243
1244 let candidate_no = ref 0;;
1245
1246 let sort_new_elems l = 
1247   List.sort (fun (_,_,_,_,l1) (_,_,_,_,l2) -> List.length l1 - List.length l2) l
1248 ;;
1249
1250 let try_candidate flags depth status t =
1251  try
1252    debug_print ~depth (lazy ("try " ^ CicNotationPp.pp_term t));
1253    let status = NTactics.apply_tac ("",0,t) status in
1254    let open_goals = head_goals status#stack in
1255    debug_print ~depth
1256      (lazy ("success: "^String.concat " "(List.map string_of_int open_goals)));
1257    if List.length open_goals > flags.maxwidth || 
1258       (depth = flags.maxdepth && open_goals <> []) then
1259       (debug_print ~depth (lazy "pruned immediately"); None)
1260    else
1261      (incr candidate_no;
1262       Some ((!candidate_no,t),status,open_goals))
1263  with Error (msg,exn) -> debug_print ~depth (lazy "failed"); None
1264 ;;
1265
1266 let get_candidates status cache signature gty =
1267   let universe = status#auto_cache in
1268   let context = ctx_of gty in
1269   let _, raw_gty = term_of_cic_term status gty context in
1270   let cands = NDiscriminationTree.DiscriminationTree.retrieve_unifiables 
1271         universe raw_gty
1272   in
1273   let cands = 
1274     List.filter (only signature context) 
1275       (NDiscriminationTree.TermSet.elements cands)
1276   in
1277   List.map (fun t -> 
1278      let _status, t = term_of_cic_term status t context in Ast.NCic t) 
1279      (search_in_th gty cache)
1280   @ 
1281   List.map (function NCic.Const r -> Ast.NRef r | _ -> assert false) cands
1282 ;;
1283
1284 let applicative_case depth signature status flags gty cache =
1285   let tcache,_ = cache in
1286   app_counter:= !app_counter+1; 
1287   let candidates = get_candidates status tcache signature gty in
1288   debug_print ~depth
1289     (lazy ("candidates: " ^ string_of_int (List.length candidates)));
1290   let elems = 
1291     List.fold_left 
1292       (fun elems cand ->
1293         match try_candidate flags depth status cand with
1294         | None -> elems
1295         | Some x -> x::elems)
1296       [] candidates
1297   in
1298   elems
1299 ;;
1300
1301 exception Found
1302 ;;
1303
1304 (* gty is supposed to be meta-closed *)
1305 let is_subsumed depth status gty (_,cache) =
1306   if cache=[] then false else (
1307   debug_print ~depth (lazy("Subsuming " ^ (ppterm status gty))); 
1308   let n,h,metasenv,subst,obj = status#obj in
1309   let ctx = ctx_of gty in
1310   let _ , target = term_of_cic_term status gty ctx in
1311   let target = NCicSubstitution.lift 1 target in 
1312   (* candidates must only be searched w.r.t the given context *)
1313   let candidates = 
1314     try
1315     let idx = List.assq ctx cache in
1316       Ncic_termSet.elements 
1317         (InvRelDiscriminationTree.retrieve_generalizations idx gty)
1318     with Not_found -> []
1319   in
1320   debug_print ~depth
1321     (lazy ("failure candidates: " ^ string_of_int (List.length candidates)));
1322     try
1323       List.iter
1324         (fun t ->
1325            let _ , source = term_of_cic_term status t ctx in
1326            let implication = 
1327              NCic.Prod("foo",source,target) in
1328            let metasenv,j,_,_ = 
1329              NCicMetaSubst.mk_meta  
1330                metasenv ctx ~with_type:implication `IsType in
1331            let status = status#set_obj (n,h,metasenv,subst,obj) in
1332            let status = status#set_stack [([1,Open j],[],[],`NoTag)] in 
1333            try
1334              let status = NTactics.intro_tac "foo" status in
1335              let status =
1336                NTactics.apply_tac ("",0,Ast.NCic (NCic.Rel 1)) status
1337              in 
1338                if (head_goals status#stack = []) then raise Found
1339                else ()
1340            with
1341              | Error _ -> ())
1342         candidates;false
1343     with Found -> debug_print ~depth (lazy "success");true)
1344 ;;
1345
1346
1347 let equational_and_applicative_case
1348   signature flags status g depth gty cache 
1349 =
1350  let elems = 
1351   if false (*is_equational_case gty flags*) then
1352     let elems =
1353       equational_case
1354         signature status flags g gty cache 
1355     in
1356     let more_elems =
1357         applicative_case depth
1358           signature status flags gty cache 
1359     in
1360       elems@more_elems
1361   else
1362     let elems =
1363       (*match LibraryObjects.eq_URI () with
1364       | Some _ ->
1365          smart_applicative_case dbd tables depth s fake_proof goalno 
1366            gty m context signature universe cache flags
1367       | None -> *)
1368          applicative_case depth
1369           signature status flags gty cache 
1370     in
1371       elems
1372  in
1373  let elems = 
1374    List.map (fun c,s,gl -> 
1375        c,1,1,s,List.map (fun i -> 
1376                       let sort = 
1377                         let gty = get_goalty s i in
1378                         let _, sort = typeof s (ctx_of gty) gty in
1379                           match term_of_cic_term s sort (ctx_of sort) with
1380                             | _, NCic.Sort NCic.Prop -> P
1381                             | _ -> T
1382                       in
1383                         i,sort) gl) elems 
1384  in
1385  (* let elems = sort_new_elems elems in *)
1386  elems, cache
1387 ;;
1388
1389 (* warning: ctx is supposed to be already instantiated w.r.t subst *)
1390 let index_local_equations eq_cache ctx =
1391   let c = ref 0 in
1392   List.fold_left 
1393     (fun cache _ ->
1394        c:= !c+1;
1395        let t = NCic.Rel 1 in
1396          try
1397            let ty = NCicTypeChecker.typeof [] [] ctx t in
1398              NCicParamod.forward_infer_step eq_cache t ty
1399          with 
1400            | NCicTypeChecker.TypeCheckerFailure _
1401            | NCicTypeChecker.AssertFailure _ -> eq_cache) 
1402     eq_cache ctx
1403 ;;
1404
1405 let rec guess_name name ctx = 
1406   if name = "_" then guess_name "auto" ctx else
1407   if not (List.mem_assoc name ctx) then name else
1408   guess_name (name^"'") ctx
1409 ;;
1410
1411 let intro ~depth status (tcache,fcache) name =
1412   let status = NTactics.intro_tac name status in
1413   let open_goals = head_goals status#stack in
1414   assert (List.length open_goals  = 1);
1415   let open_goal = List.hd open_goals in
1416   let ngty = get_goalty status open_goal in
1417   let ctx = ctx_of ngty in
1418   let t = mk_cic_term ctx (NCic.Rel 1) in
1419   let status, keys = keys_of_term status t in
1420   let tcache = List.fold_left (add_to_th t) tcache keys in
1421     debug_print ~depth (lazy ("intro: "^ string_of_int open_goal));
1422   (* unprovability is not stable w.r.t introduction *)
1423   status, (tcache,[])
1424 ;;
1425
1426 let rec intros ~depth status cache =
1427   let open_goals = head_goals status#stack in
1428   assert (List.length open_goals  = 1);
1429   let open_goal = List.hd open_goals in
1430   let gty = get_goalty status open_goal in
1431   let _, raw_gty = term_of_cic_term status gty (ctx_of gty) in
1432   match raw_gty with
1433     | NCic.Prod (name,_,_) ->
1434         let status,cache =
1435           intro ~depth status cache (guess_name name (ctx_of gty))
1436         in intros ~depth status cache 
1437     | _ -> status, cache, open_goal
1438 ;;
1439
1440 let reduce ~depth status g = 
1441   let n,h,metasenv,subst,o = status#obj in 
1442   let attr, ctx, ty = NCicUtils.lookup_meta g metasenv in
1443   let ty = NCicUntrusted.apply_subst subst ctx ty in
1444   let ty' = NCicReduction.whd ~subst ctx ty in
1445   if ty = ty' then []
1446   else
1447     (debug_print ~depth 
1448       (lazy ("reduced to: "^ NCicPp.ppterm ctx subst metasenv ty'));
1449     let metasenv = 
1450       (g,(attr,ctx,ty'))::(List.filter (fun (i,_) -> i<>g) metasenv) 
1451     in
1452     let status = status#set_obj (n,h,metasenv,subst,o) in
1453     incr candidate_no;
1454     [(!candidate_no,Ast.Implicit `JustOne),0,0,status,[g,P]])
1455 ;;
1456
1457 let do_something signature flags status g depth gty cache =
1458   let l = reduce ~depth status g in
1459   let l1,cache =
1460       (equational_and_applicative_case 
1461          signature flags status g depth gty cache)
1462   in
1463     sort_new_elems (l@l1), cache
1464 ;;
1465
1466 let pp_goal = function
1467   | (_,Continuationals.Stack.Open i) 
1468   | (_,Continuationals.Stack.Closed i) -> string_of_int i 
1469 ;;
1470
1471 let pp_goals status l =
1472   String.concat ", " 
1473     (List.map 
1474        (fun i -> 
1475           let gty = get_goalty status i in
1476             NTacStatus.ppterm status gty)
1477        l)
1478 ;;
1479
1480 module M = 
1481   struct 
1482     type t = int
1483     let compare = Pervasives.compare
1484   end
1485 ;;
1486
1487 module MS = HTopoSort.Make(M)
1488 ;;
1489
1490 let sort_tac status =
1491   let gstatus = 
1492     match status#stack with
1493     | [] -> assert false
1494     | (goals, t, k, tag) :: s ->
1495         let g = head_goals status#stack in
1496         let sortedg = 
1497           (List.rev (MS.topological_sort g (deps status))) in
1498           debug_print (lazy ("old g = " ^ 
1499             String.concat "," (List.map string_of_int g)));
1500           debug_print (lazy ("sorted goals = " ^ 
1501             String.concat "," (List.map string_of_int sortedg)));
1502           let is_it i = function
1503             | (_,Continuationals.Stack.Open j ) 
1504             | (_,Continuationals.Stack.Closed j ) -> i = j
1505           in 
1506           let sorted_goals = 
1507             List.map (fun i -> List.find (is_it i) goals) sortedg
1508           in
1509             (sorted_goals, t, k, tag) :: s
1510   in
1511    status#set_stack gstatus
1512 ;;
1513   
1514 let clean_up_tac status =
1515   let gstatus = 
1516     match status#stack with
1517     | [] -> assert false
1518     | (g, t, k, tag) :: s ->
1519         let is_open = function
1520           | (_,Continuationals.Stack.Open _) -> true
1521           | (_,Continuationals.Stack.Closed _) -> false
1522         in
1523         let g' = List.filter is_open g in
1524           (g', t, k, tag) :: s
1525   in
1526    status#set_stack gstatus
1527 ;;
1528
1529 let focus_tac focus status =
1530   let gstatus = 
1531     match status#stack with
1532     | [] -> assert false
1533     | (g, t, k, tag) :: s ->
1534         let in_focus = function
1535           | (_,Continuationals.Stack.Open i) 
1536           | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1537         in
1538         let focus,others = List.partition in_focus g
1539         in
1540           (* we need to mark it as a BranchTag, otherwise cannot merge later *)
1541           (focus,[],[],`BranchTag) :: (others, t, k, tag) :: s
1542   in
1543    status#set_stack gstatus
1544 ;;
1545
1546 let rec auto_clusters 
1547     flags signature cache depth status : unit =
1548   debug_print ~depth (lazy "entering auto clusters");
1549   (* ignore(Unix.select [] [] [] 0.01); *)
1550   let status = clean_up_tac status in
1551   let goals = head_goals status#stack in
1552   if goals = [] then raise (Proved status)
1553   else if depth = flags.maxdepth then raise (Gaveup IntSet.empty)
1554   else if List.length goals < 2 then 
1555     auto_main flags signature cache depth status 
1556   else
1557     debug_print ~depth (lazy ("goals = " ^ 
1558       String.concat "," (List.map string_of_int goals)));
1559     let classes = HExtlib.clusters (deps status) goals in
1560       debug_print ~depth
1561         (lazy 
1562            (String.concat "\n" 
1563            (List.map
1564               (fun l -> 
1565                  ("cluster:" ^ String.concat "," (List.map string_of_int l)))
1566            classes)));
1567       let status = 
1568         List.fold_left
1569           (fun status gl -> 
1570              let status = focus_tac gl status in
1571              try 
1572                debug_print ~depth (lazy ("focusing on" ^ 
1573                               String.concat "," (List.map string_of_int gl)));
1574                auto_main flags signature cache depth status; status
1575              with Proved(status) -> NTactics.merge_tac status)
1576           status classes
1577       in raise (Proved status)
1578
1579 and
1580
1581 (* let rec auto_main flags signature cache status k depth = *)
1582
1583 auto_main flags signature cache depth status: unit =
1584   debug_print ~depth (lazy "entering auto main");
1585   (* ignore(Unix.select [] [] [] 0.01); *)
1586   let status = sort_tac (clean_up_tac status) in
1587   let goals = head_goals status#stack in
1588   match goals with
1589     | [] -> raise (Proved status)
1590     | g::tlg ->
1591         if depth = flags.maxdepth then raise (Gaveup IntSet.empty)
1592         else
1593         let status = 
1594           if tlg=[] then status 
1595           else NTactics.branch_tac status in
1596         let status, cache, g = intros ~depth status cache in
1597         let gty = get_goalty status g in
1598         let ctx,ty = close status g in
1599         let closegty = mk_cic_term ctx ty in
1600         let status, gty = apply_subst status (ctx_of gty) gty in
1601         debug_print ~depth (lazy("Attacking goal " ^ (string_of_int g) ^" : "^ppterm status gty)); 
1602         if is_subsumed depth status closegty cache then 
1603           (debug_print (lazy "SUBSUMED");
1604            raise (Gaveup IntSet.add g IntSet.empty))
1605         else 
1606         let alternatives, cache = 
1607           do_something signature flags status g depth gty cache in
1608         let loop_cache =         
1609           let tcache,fcache = cache in
1610             tcache,add_to_th closegty fcache closegty in
1611         let unsat =
1612           List.fold_left
1613             (* the underscore information does not need to be returned
1614                by do_something *)
1615             (fun unsat ((_,t),_,_,status,_) ->
1616                let depth',looping_cache = 
1617                  if t=(Ast.Implicit `JustOne) then depth,cache 
1618                  else depth+1, loop_cache in
1619                debug_print (~depth:depth') 
1620                  (lazy ("Case: " ^ CicNotationPp.pp_term t));
1621                try auto_clusters flags signature loop_cache
1622                  depth' status; unsat
1623                with 
1624                  | Proved status ->
1625                      debug_print (~depth:depth') (lazy "proved");
1626                      if tlg=[] then raise (Proved status) 
1627                      else 
1628                        let status = NTactics.merge_tac status
1629                      in
1630                      ( (* old cache, here *)
1631                        try auto_clusters flags signature cache 
1632                         depth status; assert false
1633                       with Gaveup f ->
1634                         debug_print ~depth 
1635                           (lazy ("Unsat1 at depth " ^ (string_of_int depth)
1636                                    ^ ": " ^ 
1637                                    (pp_goals status (IntSet.elements f))));
1638                         (* TODO: cache failures *)
1639                         IntSet.union f unsat)
1640                  | Gaveup f -> 
1641                      debug_print (~depth:depth')
1642                        (lazy ("Unsat2 at depth " ^ (string_of_int depth')
1643                               ^ ": " ^ 
1644                               (pp_goals status (IntSet.elements f))));
1645                      (* TODO: cache local failures *)
1646                      unsat)
1647             IntSet.empty alternatives
1648         in
1649           raise (Gaveup IntSet.add g unsat)
1650 ;;
1651                  
1652 let int name l def = 
1653   try int_of_string (List.assoc name l)
1654   with Failure _ | Not_found -> def
1655 ;;
1656
1657 let auto_tac ~params:(_univ,flags) status =
1658   let goals = head_goals status#stack in
1659   let status, cache = mk_th_cache status goals in
1660 (*   pp_th status cache; *)
1661 (*
1662   NDiscriminationTree.DiscriminationTree.iter status#auto_cache (fun p t -> 
1663     debug_print (lazy(
1664       NDiscriminationTree.NCicIndexable.string_of_path p ^ " |--> " ^
1665       String.concat "\n    " (List.map (
1666       NCicPp.ppterm ~metasenv:[] ~context:[] ~subst:[])
1667         (NDiscriminationTree.TermSet.elements t))
1668       )));
1669 *)
1670   let depth = int "depth" flags 3 in 
1671   let size  = int "size" flags 10 in 
1672   let width = int "width" flags (3+List.length goals) in 
1673   (* XXX fix sort *)
1674   let goals = List.map (fun i -> (i,P)) goals in
1675   let signature = () in
1676   let flags = { 
1677           maxwidth = width;
1678           maxsize = size;
1679           maxdepth = depth;
1680           timeout = Unix.gettimeofday() +. 3000.;
1681           do_types = false; 
1682   } in
1683   let initial_time = Unix.gettimeofday() in
1684   app_counter:= 0;
1685   let rec up_to x y =
1686     if x > y then
1687       (print(lazy
1688         ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1689        print(lazy
1690         ("Applicative nodes:"^string_of_int !app_counter)); 
1691        raise (Error (lazy "auto gave up", None)))
1692     else
1693       let _ = debug_print (lazy("\n\nRound "^string_of_int x^"\n")) in
1694       let flags = { flags with maxdepth = x } 
1695       in 
1696         try auto_clusters flags signature (cache,[]) 0 status;status 
1697         with
1698           | Gaveup _ -> up_to (x+1) y
1699           | Proved s -> 
1700               print (lazy ("proved at depth " ^ string_of_int x));
1701               let stack = 
1702                 match s#stack with
1703                   | (g,t,k,f) :: rest -> (filter_open g,t,k,f):: rest
1704                   | _ -> assert false
1705               in
1706                 s#set_stack stack
1707   in
1708   let s = up_to depth depth in
1709     print(lazy
1710         ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1711     print(lazy
1712         ("Applicative nodes:"^string_of_int !app_counter));
1713     s
1714 ;;
1715