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