]> matita.cs.unibo.it Git - helm.git/blob - matita/components/ng_tactics/nnAuto.ml
Many changes
[helm.git] / matita / 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 print ?(depth=0) s = 
15   prerr_endline (String.make (2*depth) ' '^Lazy.force s) 
16 let noprint ?(depth=0) _ = () 
17 let debug_print = noprint
18
19 open Continuationals.Stack
20 open NTacStatus
21 module Ast = NotationPt
22
23 (* ======================= statistics  ========================= *)
24
25 let app_counter = ref 0
26
27 module RHT = struct
28   type t = NReference.reference
29   let equal = NReference.eq
30   let compare = NReference.compare
31   let hash = NReference.hash
32 end;;
33
34 module RefHash = Hashtbl.Make(RHT);;
35
36 type info = {
37   nominations : int ref;
38   uses: int ref;
39 }
40
41 let statistics: info RefHash.t = RefHash.create 503
42
43 let incr_nominations tbl item =
44   try
45     let v = RefHash.find tbl item in incr v.nominations
46   with Not_found ->
47     RefHash.add tbl item {nominations = ref 1; uses = ref 0}
48
49 let incr_uses tbl item =
50   try
51     let v = RefHash.find tbl item in incr v.uses
52   with Not_found -> assert false
53
54 let toref f tbl t =
55   match t with
56     | Ast.NRef n -> 
57         f tbl n
58     | Ast.NCic _  (* local candidate *)
59     | _  ->  ()
60
61 let is_relevant tbl item =
62   try
63     let v = RefHash.find tbl item in
64       if !(v.nominations) < 60 then true (* not enough info *)
65       else if !(v.uses) = 0 then false
66       else true
67   with Not_found -> true
68
69 let print_stat status tbl =
70   let l = RefHash.fold (fun a v l -> (a,v)::l) tbl [] in
71   let relevance v = float !(v.uses) /. float !(v.nominations) in
72   let vcompare (_,v1) (_,v2) =
73     Pervasives.compare (relevance v1) (relevance v2) in
74   let l = List.sort vcompare l in
75   let short_name r = 
76     Filename.chop_extension 
77       (Filename.basename (NReference.string_of_reference r))
78   in
79   let vstring (a,v)=
80       short_name a ^ ": rel = " ^
81       (string_of_float (relevance v)) ^
82       "; uses = " ^ (string_of_int !(v.uses)) ^
83       "; nom = " ^ (string_of_int !(v.nominations)) in
84   lazy ("\n\nSTATISTICS:\n" ^
85           String.concat "\n" (List.map vstring l)) 
86
87 (* ======================= utility functions ========================= *)
88 module IntSet = Set.Make(struct type t = int let compare = compare end)
89
90 let get_sgoalty status g =
91  let _,_,metasenv,subst,_ = status#obj in
92  try
93    let _, ctx, ty = NCicUtils.lookup_meta g metasenv in
94    let ty = NCicUntrusted.apply_subst status subst ctx ty in
95    let ctx = NCicUntrusted.apply_subst_context status
96      ~fix_projections:true subst ctx
97    in
98      NTacStatus.mk_cic_term ctx ty
99  with NCicUtils.Meta_not_found _ as exn -> fail ~exn (lazy "get_sgoalty")
100 ;;
101
102 let deps status g =
103   let gty = get_sgoalty status g in
104   metas_of_term status gty
105 ;;
106
107 let menv_closure status gl = 
108   let rec closure acc = function
109     | [] -> acc
110     | x::l when IntSet.mem x acc -> closure acc l
111     | x::l -> closure (IntSet.add x acc) (deps status x @ l)
112   in closure IntSet.empty gl
113 ;;
114
115 (* we call a "fact" an object whose hypothesis occur in the goal 
116    or in types of goal-variables *)
117 let branch status ty =  
118   let status, ty, metas = saturate ~delta:0 status ty in
119   noprint (lazy ("saturated ty :" ^ (ppterm status ty)));
120   let g_metas = metas_of_term status ty in
121   let clos = menv_closure status g_metas in
122   (* let _,_,metasenv,_,_ = status#obj in *)
123   let menv = 
124     List.fold_left
125       (fun acc m ->
126          let _, m = term_of_cic_term status m (ctx_of m) in
127          match m with 
128          | NCic.Meta(i,_) -> IntSet.add i acc
129          | _ -> assert false)
130       IntSet.empty metas
131   in 
132   (* IntSet.subset menv clos *)
133   IntSet.cardinal(IntSet.diff menv clos)
134
135 let is_a_fact status ty = branch status ty = 0
136
137 let is_a_fact_obj s uri = 
138   let obj = NCicEnvironment.get_checked_obj s uri in
139   match obj with
140     | (_,_,[],[],NCic.Constant(_,_,_,ty,_)) ->
141         is_a_fact s (mk_cic_term [] ty)
142 (* aggiungere i costruttori *)
143     | _ -> false
144
145 let is_a_fact_ast status subst metasenv ctx cand = 
146  noprint ~depth:0 
147    (lazy ("checking facts " ^ NotationPp.pp_term status cand)); 
148  let status, t = disambiguate status ctx ("",0,cand) `XTNone in
149  let status,t = term_of_cic_term status t ctx in
150  let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
151    is_a_fact status (mk_cic_term ctx ty)
152
153 let current_goal status = 
154   let open_goals = head_goals status#stack in
155   assert (List.length open_goals  = 1);
156   let open_goal = List.hd open_goals in
157   let gty = get_goalty status open_goal in
158   let ctx = ctx_of gty in
159     open_goal, ctx, gty
160
161 let height_of_ref status (NReference.Ref (uri, x)) = 
162   match x with
163   | NReference.Decl 
164   | NReference.Ind _ 
165   | NReference.Con _
166   | NReference.CoFix _ -> 
167       let _,height,_,_,_ = NCicEnvironment.get_checked_obj status uri in
168       height 
169   | NReference.Def h -> h 
170   | NReference.Fix (_,_,h) -> h 
171 ;;
172
173 (*************************** height functions ********************************)
174 let fast_height_of_term status t =
175  let h = ref 0 in
176  let rec aux =
177   function
178      NCic.Meta (_,(_,NCic.Ctx l)) -> List.iter aux l
179    | NCic.Meta _ -> ()
180    | NCic.Rel _
181    | NCic.Sort _ -> ()
182    | NCic.Implicit _ -> assert false
183    | NCic.Const nref -> 
184 (*
185                    prerr_endline (status#ppterm ~metasenv:[] ~subst:[]
186                    ~context:[] t ^ ":" ^ string_of_int (height_of_ref status nref));            
187 *)
188        h := max !h (height_of_ref status nref)
189    | NCic.Prod (_,t1,t2)
190    | NCic.Lambda (_,t1,t2) -> aux t1; aux t2
191    | NCic.LetIn (_,s,ty,t) -> aux s; aux ty; aux t
192    | NCic.Appl l -> List.iter aux l
193    | NCic.Match (_,outty,t,pl) -> aux outty; aux t; List.iter aux pl
194  in
195   aux t; !h
196 ;;
197
198 let height_of_goal g status = 
199   let ty = get_goalty status g in
200   let context = ctx_of ty in
201   let _, ty = term_of_cic_term status ty (ctx_of ty) in
202   let h = ref (fast_height_of_term status ty) in
203   List.iter 
204     (function 
205        | _, NCic.Decl ty -> h := max !h (fast_height_of_term status ty)
206        | _, NCic.Def (bo,ty) -> 
207            h := max !h (fast_height_of_term status ty);
208            h := max !h (fast_height_of_term status bo);
209     )
210     context;
211   !h
212 ;;      
213
214 let height_of_goals status = 
215   let open_goals = head_goals status#stack in
216   assert (List.length open_goals > 0);
217   let h = ref 1 in
218   List.iter 
219     (fun open_goal ->
220        h := max !h (height_of_goal open_goal status))
221      open_goals;
222   noprint (lazy ("altezza sequente: " ^ string_of_int !h));
223   !h
224 ;;
225
226 (* =============================== paramod =========================== *)
227 let solve f status eq_cache goal =
228 (*
229   let f = 
230     if fast then NCicParamod.fast_eq_check
231     else NCicParamod.paramod in
232 *)
233   let n,h,metasenv,subst,o = status#obj in
234   let gname, ctx, gty = List.assoc goal metasenv in
235   let gty = NCicUntrusted.apply_subst status subst ctx gty in
236   let build_status (pt, _, metasenv, subst) =
237     try
238       debug_print (lazy ("refining: "^(status#ppterm ctx subst metasenv pt)));
239       let stamp = Unix.gettimeofday () in 
240       let metasenv, subst, pt, pty =
241         (* NCicRefiner.typeof status
242           (* (status#set_coerc_db NCicCoercion.empty_db) *)
243           metasenv subst ctx pt None in
244           debug_print (lazy ("refined: "^(status#ppterm ctx subst metasenv pt)));
245           noprint (lazy ("synt: "^(status#ppterm ctx subst metasenv pty)));
246           let metasenv, subst =
247             NCicUnification.unify status metasenv subst ctx gty pty *)
248         NCicRefiner.typeof 
249           (status#set_coerc_db NCicCoercion.empty_db) 
250           metasenv subst ctx pt (`XTSome gty) 
251         in 
252           noprint (lazy (Printf.sprintf "Refined in %fs"
253                      (Unix.gettimeofday() -. stamp))); 
254           let status = status#set_obj (n,h,metasenv,subst,o) in
255           let metasenv = List.filter (fun j,_ -> j <> goal) metasenv in
256           let subst = (goal,(gname,ctx,pt,pty)) :: subst in
257             Some (status#set_obj (n,h,metasenv,subst,o))
258     with 
259         NCicRefiner.RefineFailure msg 
260       | NCicRefiner.Uncertain msg ->
261           debug_print (lazy ("WARNING U: refining in fast_eq_check failed\n" ^
262                         snd (Lazy.force msg) ^        
263                         "\n in the environment\n" ^ 
264                         status#ppmetasenv subst metasenv)); None
265       | NCicRefiner.AssertFailure msg -> 
266           debug_print (lazy ("WARNING F: refining in fast_eq_check failed" ^
267                         Lazy.force msg ^
268                         "\n in the environment\n" ^ 
269                         status#ppmetasenv subst metasenv)); None
270       | Sys.Break as e -> raise e
271       | _ -> None
272     in
273     HExtlib.filter_map build_status
274       (f status metasenv subst ctx eq_cache (NCic.Rel ~-1,gty))
275 ;;
276
277 let fast_eq_check eq_cache status (goal:int) =
278   match solve NCicParamod.fast_eq_check status eq_cache goal with
279   | [] -> raise (Error (lazy "no proof found",None))
280   | s::_ -> s
281 ;;
282
283 let dist_fast_eq_check eq_cache s = 
284   NTactics.distribute_tac (fast_eq_check eq_cache) s
285 ;;
286
287 let auto_eq_check eq_cache status =
288   try 
289     let s = dist_fast_eq_check eq_cache status in
290       [s]
291   with
292     | Error _ -> debug_print (lazy ("no paramod proof found"));[]
293 ;;
294
295 let index_local_equations eq_cache ?(flag=false) status =
296  if flag then
297   NCicParamod.empty_state
298  else begin
299   noprint (lazy "indexing equations");
300   let open_goals = head_goals status#stack in
301   let open_goal = List.hd open_goals in
302   let ngty = get_goalty status open_goal in
303   let _,_,metasenv,subst,_ = status#obj in
304   let ctx = apply_subst_context ~fix_projections:true status (ctx_of ngty) in
305   let c = ref 0 in
306   List.fold_left 
307     (fun eq_cache _ ->
308        c:= !c+1;
309        let t = NCic.Rel !c in
310          try
311            let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
312            if is_a_fact status (mk_cic_term ctx ty) then
313              (debug_print(lazy("eq indexing " ^ (status#ppterm ctx subst metasenv ty)));
314               NCicParamod.forward_infer_step status metasenv subst ctx eq_cache t ty)
315            else 
316              (noprint (lazy ("not a fact: " ^ (status#ppterm ctx subst metasenv ty)));
317               eq_cache)
318          with 
319            | NCicTypeChecker.TypeCheckerFailure _
320            | NCicTypeChecker.AssertFailure _ -> eq_cache) 
321     eq_cache ctx
322  end
323 ;;
324
325 let index_local_equations2 eq_cache status open_goal lemmas ?(flag=false) nohyps =
326   noprint (lazy "indexing equations");
327   let eq_cache,lemmas =
328    match lemmas with
329       None -> eq_cache,[]
330     | Some l -> NCicParamod.empty_state,l
331   in
332   let ngty = get_goalty status open_goal in
333   let _,_,metasenv,subst,_ = status#obj in
334   let ctx = apply_subst_context ~fix_projections:true status (ctx_of ngty) in
335   let status,lemmas =
336    List.fold_left
337     (fun (status,lemmas) l ->
338       let status,l = NTacStatus.disambiguate status ctx l `XTNone in
339       let status,l = NTacStatus.term_of_cic_term status l ctx in
340        status,l::lemmas)
341     (status,[]) lemmas in
342   let local_equations =
343    if nohyps then [] else
344     List.map (fun i -> NCic.Rel (i + 1))
345      (HExtlib.list_seq 1 (List.length ctx)) in
346   let lemmas = lemmas @ local_equations in
347   List.fold_left 
348     (fun eq_cache t ->
349          try
350            let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
351            if is_a_fact status (mk_cic_term ctx ty) then
352              (debug_print(lazy("eq indexing " ^ (status#ppterm ctx subst metasenv ty)));
353               NCicParamod.forward_infer_step status metasenv subst ctx eq_cache t ty)
354            else 
355              (noprint (lazy ("not a fact: " ^ (status#ppterm ctx subst metasenv ty)));
356               eq_cache)
357          with 
358            | NCicTypeChecker.TypeCheckerFailure _
359            | NCicTypeChecker.AssertFailure _ -> eq_cache)
360     eq_cache lemmas
361 ;;
362
363 let fast_eq_check_tac ~params s = 
364   let unit_eq = index_local_equations s#eq_cache s in   
365   dist_fast_eq_check unit_eq s
366 ;;
367
368 let paramod eq_cache status goal =
369   match solve NCicParamod.paramod status eq_cache goal with
370   | [] -> raise (Error (lazy "no proof found",None))
371   | s::_ -> s
372 ;;
373
374 let paramod_tac ~params s = 
375   let unit_eq = index_local_equations s#eq_cache s in   
376   NTactics.distribute_tac (paramod unit_eq) s
377 ;;
378
379 let demod eq_cache status goal =
380   match solve NCicParamod.demod status eq_cache goal with
381   | [] -> raise (Error (lazy "no progress",None))
382   | s::_ -> s
383 ;;
384
385 let demod_tac ~params s = 
386   let unit_eq s i =
387    index_local_equations2 s#eq_cache s i (fst params)
388     (List.mem_assoc "nohyps" (snd params))
389   in   
390    NTactics.distribute_tac (fun s i -> demod (unit_eq s i) s i) s
391 ;;
392
393 (*
394 let fast_eq_check_tac_all  ~params eq_cache status = 
395   let g,_,_ = current_goal status in
396   let allstates = fast_eq_check_all status eq_cache g in
397   let pseudo_low_tac s _ _ = s in
398   let pseudo_low_tactics = 
399     List.map pseudo_low_tac allstates 
400   in
401     List.map (fun f -> NTactics.distribute_tac f status) pseudo_low_tactics
402 ;;
403 *)
404
405 (*
406 let demod status eq_cache goal =
407   let n,h,metasenv,subst,o = status#obj in
408   let gname, ctx, gty = List.assoc goal metasenv in
409   let gty = NCicUntrusted.apply_subst subst ctx gty in
410
411 let demod_tac ~params s = 
412   let unit_eq = index_local_equations s#eq_cache s in   
413   dist_fast_eq_check unit_eq s
414 *)
415
416 (*************** subsumption ****************)
417
418 let close_wrt_context status =
419   List.fold_left 
420     (fun ty ctx_entry -> 
421         match ctx_entry with 
422        | name, NCic.Decl t -> NCic.Prod(name,t,ty)
423        | name, NCic.Def(bo, _) -> NCicSubstitution.subst status bo ty)
424 ;;
425
426 let args_for_context ?(k=1) ctx =
427   let _,args =
428     List.fold_left 
429       (fun (n,l) ctx_entry -> 
430          match ctx_entry with 
431            | name, NCic.Decl t -> n+1,NCic.Rel(n)::l
432            | name, NCic.Def(bo, _) -> n+1,l)
433       (k,[]) ctx in
434     args
435
436 let constant_for_meta status ctx ty i =
437   let name = "cic:/foo"^(string_of_int i)^".con" in
438   let uri = NUri.uri_of_string name in
439   let ty = close_wrt_context status ty ctx in
440   (* prerr_endline (status#ppterm [] [] [] ty); *)
441   let attr = (`Generated,`Definition,`Local) in
442   let obj = NCic.Constant([],name,None,ty,attr) in
443     (* Constant  of relevance * string * term option * term * c_attr *)
444     (uri,0,[],[],obj)
445
446 (* not used *)
447 let refresh metasenv =
448   List.fold_left 
449     (fun (metasenv,subst) (i,(iattr,ctx,ty)) ->
450        let ikind = NCicUntrusted.kind_of_meta iattr in
451        let metasenv,j,instance,ty = 
452          NCicMetaSubst.mk_meta ~attrs:iattr 
453            metasenv ctx ~with_type:ty ikind in
454        let s_entry = i,(iattr, ctx, instance, ty) in
455        let metasenv = List.filter (fun x,_ -> i <> x) metasenv in
456          metasenv,s_entry::subst) 
457       (metasenv,[]) metasenv
458
459 (* close metasenv returns a ground instance of all the metas in the
460 metasenv, insantiatied with axioms, and the list of these axioms *)
461 let close_metasenv status metasenv subst = 
462   (*
463   let metasenv = NCicUntrusted.apply_subst_metasenv subst metasenv in
464   *)
465   let metasenv = NCicUntrusted.sort_metasenv status subst metasenv in 
466     List.fold_left 
467       (fun (subst,objs) (i,(iattr,ctx,ty)) ->
468          let ty = NCicUntrusted.apply_subst status subst ctx ty in
469          let ctx = 
470            NCicUntrusted.apply_subst_context status ~fix_projections:true 
471              subst ctx in
472          let (uri,_,_,_,obj) as okind = 
473            constant_for_meta status ctx ty i in
474          try
475            NCicEnvironment.check_and_add_obj status okind;
476            let iref = NReference.reference_of_spec uri NReference.Decl in
477            let iterm =
478              let args = args_for_context ctx in
479                if args = [] then NCic.Const iref 
480                else NCic.Appl(NCic.Const iref::args)
481            in
482            (* prerr_endline (status#ppterm ctx [] [] iterm); *)
483            let s_entry = i, ([], ctx, iterm, ty)
484            in s_entry::subst,okind::objs
485          with
486             Sys.Break as e -> raise e
487           | _ -> assert false)
488       (subst,[]) metasenv
489 ;;
490
491 let ground_instances status gl =
492   let _,_,metasenv,subst,_ = status#obj in
493   let subset = menv_closure status gl in
494   let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
495 (*
496   let submenv = metasenv in
497 *)
498   let subst, objs = close_metasenv status submenv subst in
499   try
500     List.iter
501       (fun i -> 
502          let (_, ctx, t, _) = List.assoc i subst in
503            noprint (lazy (status#ppterm ctx [] [] t));
504            List.iter 
505              (fun (uri,_,_,_,_) as obj -> 
506                 NCicEnvironment.invalidate_item (`Obj (uri, obj))) 
507              objs;
508            ())
509       gl
510   with
511       Not_found -> assert false 
512   (* (ctx,t) *)
513 ;;
514
515 let replace_meta status i args target = 
516   let rec aux k = function
517     (* TODO: local context *)
518     | NCic.Meta (j,lc) when i = j ->
519         (match args with
520            | [] -> NCic.Rel 1
521            | _ -> let args = 
522                List.map (NCicSubstitution.subst_meta status lc) args in
523                NCic.Appl(NCic.Rel k::args))
524     | NCic.Meta (j,lc) as m ->
525         (match lc with
526            _,NCic.Irl _ -> m
527          | n,NCic.Ctx l ->
528             NCic.Meta
529              (i,(0,NCic.Ctx
530                  (List.map (fun t ->
531                    aux k (NCicSubstitution.lift status n t)) l))))
532     | t -> NCicUtils.map status (fun _ k -> k+1) k aux t
533  in
534    aux 1 target
535 ;;
536
537 let close_wrt_metasenv status subst =
538   List.fold_left 
539     (fun ty (i,(iattr,ctx,mty)) ->
540        let mty = NCicUntrusted.apply_subst status subst ctx mty in
541        let ctx = 
542          NCicUntrusted.apply_subst_context status ~fix_projections:true 
543            subst ctx in
544        let cty = close_wrt_context status mty ctx in
545        let name = "foo"^(string_of_int i) in
546        let ty = NCicSubstitution.lift status 1 ty in
547        let args = args_for_context ~k:1 ctx in
548          (* prerr_endline (status#ppterm ctx [] [] iterm); *)
549        let ty = replace_meta status i args ty
550        in
551        NCic.Prod(name,cty,ty))
552 ;;
553
554 let close status g =
555   let _,_,metasenv,subst,_ = status#obj in
556   let subset = menv_closure status [g] in
557   let subset = IntSet.remove g subset in
558   let elems = IntSet.elements subset in 
559   let _, ctx, ty = NCicUtils.lookup_meta g metasenv in
560   let ty = NCicUntrusted.apply_subst status subst ctx ty in
561   noprint (lazy ("metas in " ^ (status#ppterm ctx [] metasenv ty)));
562   noprint (lazy (String.concat ", " (List.map string_of_int elems)));
563   let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
564   let submenv = List.rev (NCicUntrusted.sort_metasenv status subst submenv) in 
565 (*  
566     let submenv = metasenv in
567 *)
568   let ty = close_wrt_metasenv status subst ty submenv in
569     noprint (lazy (status#ppterm ctx [] [] ty));
570     ctx,ty
571 ;;
572
573 (****************** smart application ********************)
574
575 let saturate_to_ref status metasenv subst ctx nref ty =
576   let height = height_of_ref status nref in
577   let rec aux metasenv ty args = 
578     let ty,metasenv,moreargs =  
579       NCicMetaSubst.saturate status ~delta:height metasenv subst ctx ty 0 in 
580     match ty with
581       | NCic.Const(NReference.Ref (_,NReference.Def _) as nre) 
582           when nre<>nref ->
583           let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in 
584             aux metasenv bo (args@moreargs)
585       | NCic.Appl(NCic.Const(NReference.Ref (_,NReference.Def _) as nre)::tl) 
586           when nre<>nref ->
587           let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in
588             aux metasenv (NCic.Appl(bo::tl)) (args@moreargs) 
589     | _ -> ty,metasenv,(args@moreargs)
590   in
591     aux metasenv ty []
592
593 let smart_apply t unit_eq status g = 
594   let n,h,metasenv,subst,o = status#obj in
595   let gname, ctx, gty = List.assoc g metasenv in
596   (* let ggty = mk_cic_term context gty in *)
597   let status, t = disambiguate status ctx t `XTNone in
598   let status,t = term_of_cic_term status t ctx in
599   let _,_,metasenv,subst,_ = status#obj in
600   let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
601   let ty,metasenv,args = 
602     match gty with
603       | NCic.Const(nref)
604       | NCic.Appl(NCic.Const(nref)::_) -> 
605           saturate_to_ref status metasenv subst ctx nref ty
606       | _ -> 
607           NCicMetaSubst.saturate status metasenv subst ctx ty 0 in
608   let metasenv,j,inst,_ = NCicMetaSubst.mk_meta metasenv ctx `IsTerm in
609   let status = status#set_obj (n,h,metasenv,subst,o) in
610   let pterm = if args=[] then t else 
611     match t with
612       | NCic.Appl l -> NCic.Appl(l@args) 
613       | _ -> NCic.Appl(t::args) 
614   in
615   noprint(lazy("pterm " ^ (status#ppterm ctx [] [] pterm)));
616   noprint(lazy("pty " ^ (status#ppterm ctx [] [] ty)));
617   let eq_coerc =       
618     let uri = 
619       NUri.uri_of_string "cic:/matita/basics/logic/eq_coerc.con" in
620     let ref = NReference.reference_of_spec uri (NReference.Def(2)) in
621       NCic.Const ref
622   in
623   let smart = 
624     NCic.Appl[eq_coerc;ty;NCic.Implicit `Type;pterm;inst] in
625   let smart = mk_cic_term ctx smart in 
626     try
627       let status = instantiate status g smart in
628       let _,_,metasenv,subst,_ = status#obj in
629       let _,ctx,jty = List.assoc j metasenv in
630       let jty = NCicUntrusted.apply_subst status subst ctx jty in
631         debug_print(lazy("goal " ^ (status#ppterm ctx [] [] jty)));
632         let res = fast_eq_check unit_eq status j in
633         debug_print(lazy("ritorno da fast_eq_check"));
634         res
635     with
636       | NCicEnvironment.ObjectNotFound s as e ->
637           raise (Error (lazy "eq_coerc non yet defined",Some e))
638       | Error _ as e -> debug_print (lazy "error"); raise e
639 (* FG: for now we catch TypeCheckerFailure; to be understood *)  
640       | NCicTypeChecker.TypeCheckerFailure _ ->
641           debug_print (lazy "TypeCheckerFailure");
642           raise (Error (lazy "no proof found",None))
643 ;;
644
645 let compare_statuses ~past ~present =
646  let _,_,past,_,_ = past#obj in 
647  let _,_,present,_,_ = present#obj in 
648  List.map fst (List.filter (fun (i,_) -> not(List.mem_assoc i past)) present),
649  List.map fst (List.filter (fun (i,_) -> not (List.mem_assoc i present)) past)
650 ;;
651
652 (* paramodulation has only an implicit knoweledge of the symmetry of equality;
653    hence it is in trouble in proving (a = b) = (b = a) *) 
654 let try_sym tac status g =
655   let sym_eq = Ast.Appl [Ast.Ident("sym_eq",None); Ast.Implicit `Vector] in
656   let _,_,metasenv,subst,_ = status#obj in
657   let _, context, gty = List.assoc g metasenv in
658   let is_eq = 
659     NCicParamod.is_equation status metasenv subst context gty 
660   in
661   if is_eq then
662     try tac status g
663     with Error _ ->
664       let new_status = instantiate_with_ast status g ("",0,sym_eq) in 
665       let go, _ = compare_statuses ~past:status ~present:new_status in
666       assert (List.length go  = 1);
667       let ng = List.hd go in
668       tac new_status ng
669    else tac status g
670 ;;
671
672 let smart_apply_tac t s =
673   let unit_eq = index_local_equations s#eq_cache s in   
674   NTactics.distribute_tac (try_sym (smart_apply t unit_eq)) s 
675   (* NTactics.distribute_tac (smart_apply t unit_eq) s *)
676
677 let smart_apply_auto t eq_cache =
678   NTactics.distribute_tac (try_sym (smart_apply t eq_cache)) 
679   (* NTactics.distribute_tac (smart_apply t eq_cache) *)
680
681
682 (****************** types **************)
683
684
685 type th_cache = (NCic.context * InvRelDiscriminationTree.t) list
686
687 (* cartesian: term set list -> term list set *)
688 let rec cartesian =
689  function
690     [] -> NDiscriminationTree.TermListSet.empty
691   | [l] ->
692      NDiscriminationTree.TermSet.fold
693       (fun x acc -> NDiscriminationTree.TermListSet.add [x] acc) l NDiscriminationTree.TermListSet.empty
694   | he::tl ->
695      let rest = cartesian tl in
696       NDiscriminationTree.TermSet.fold
697        (fun x acc ->
698          NDiscriminationTree.TermListSet.fold (fun l acc' -> NDiscriminationTree.TermListSet.add (x::l) acc') rest acc
699        ) he NDiscriminationTree.TermListSet.empty
700 ;;
701
702 (* all_keys_of_cic_type: term -> term set *)
703 let all_keys_of_cic_type status metasenv subst context ty =
704  let saturate ty =
705   (* Here we are dropping the metasenv, but this should not raise any
706      exception (hopefully...) *)
707   let ty,_,hyps =
708    NCicMetaSubst.saturate status ~delta:max_int metasenv subst context ty 0
709   in
710    ty,List.length hyps
711  in
712  let rec aux ty =
713   match ty with
714      NCic.Appl (he::tl) ->
715       let tl' =
716        List.map (fun ty ->
717         let wty = NCicReduction.whd status ~delta:0 ~subst context ty in
718          if ty = wty then
719           NDiscriminationTree.TermSet.add ty (aux ty)
720          else
721           NDiscriminationTree.TermSet.union
722            (NDiscriminationTree.TermSet.add  ty (aux  ty))
723            (NDiscriminationTree.TermSet.add wty (aux wty))
724         ) tl
725       in
726        NDiscriminationTree.TermListSet.fold
727         (fun l acc -> NDiscriminationTree.TermSet.add (NCic.Appl l) acc)
728         (cartesian ((NDiscriminationTree.TermSet.singleton he)::tl'))
729         NDiscriminationTree.TermSet.empty
730    | _ -> NDiscriminationTree.TermSet.empty
731  in
732   let ty,ity = saturate ty in
733   let wty,iwty = saturate (NCicReduction.whd status ~delta:0 ~subst context ty) in
734    if ty = wty then
735     [ity, NDiscriminationTree.TermSet.add ty (aux ty)]
736    else
737     [ity,  NDiscriminationTree.TermSet.add  ty (aux  ty) ;
738      iwty, NDiscriminationTree.TermSet.add wty (aux wty) ]
739 ;;
740
741 let all_keys_of_type status t =
742  let _,_,metasenv,subst,_ = status#obj in
743  let context = ctx_of t in
744  let status, t = apply_subst status context t in
745  let keys =
746   all_keys_of_cic_type status metasenv subst context
747    (snd (term_of_cic_term status t context))
748  in
749   status,
750    List.map
751     (fun (intros,keys) ->
752       intros,
753        NDiscriminationTree.TermSet.fold
754         (fun t acc -> Ncic_termSet.add (mk_cic_term context t) acc)
755         keys Ncic_termSet.empty
756     ) keys
757 ;;
758
759
760 let keys_of_type status orig_ty =
761   (* Here we are dropping the metasenv (in the status), but this should not
762      raise any exception (hopefully...) *)
763   let _, ty, _ = saturate ~delta:max_int status orig_ty in
764   let _, ty = apply_subst status (ctx_of ty) ty in
765   let keys =
766 (*
767     let orig_ty' = NCicTacReduction.normalize ~subst context orig_ty in
768     if orig_ty' <> orig_ty then
769      let ty',_,_= NCicMetaSubst.saturate ~delta:0 metasenv subst context orig_ty' 0 in
770       [ty;ty']
771     else
772      [ty]
773 *)
774    [ty] in
775 (*CSC: strange: we keep ty, ty normalized and ty ~delta:(h-1) *)
776   let keys = 
777     let _, ty = term_of_cic_term status ty (ctx_of ty) in
778     match ty with
779     | NCic.Const (NReference.Ref (_,(NReference.Def h | NReference.Fix (_,_,h)))) 
780     | NCic.Appl (NCic.Const(NReference.Ref(_,(NReference.Def h | NReference.Fix (_,_,h))))::_) 
781        when h > 0 ->
782          let _,ty,_= saturate status ~delta:(h-1) orig_ty in
783          ty::keys
784     | _ -> keys
785   in
786   status, keys
787 ;;
788
789 let all_keys_of_term status t =
790  let status, orig_ty = typeof status (ctx_of t) t in
791   all_keys_of_type status orig_ty
792 ;;
793
794 let keys_of_term status t =
795   let status, orig_ty = typeof status (ctx_of t) t in
796     keys_of_type status orig_ty
797 ;;
798
799 let mk_th_cache status gl = 
800   List.fold_left 
801     (fun (status, acc) g ->
802        let gty = get_goalty status g in
803        let ctx = ctx_of gty in
804        noprint(lazy("th cache for: "^ppterm status gty));
805        noprint(lazy("th cache in: "^ppcontext status ctx));
806        if List.mem_assq ctx acc then status, acc else
807          let idx = InvRelDiscriminationTree.empty in
808          let status,_,idx = 
809            List.fold_left 
810              (fun (status, i, idx) _ -> 
811                 let t = mk_cic_term ctx (NCic.Rel i) in
812                 let status, keys = keys_of_term status t in
813                 noprint(lazy("indexing: "^ppterm status t ^ ": " ^ string_of_int (List.length keys)));
814                 let idx =
815                   List.fold_left (fun idx k -> 
816                     InvRelDiscriminationTree.index idx k t) idx keys
817                 in
818                 status, i+1, idx)
819              (status, 1, idx) ctx
820           in
821          status, (ctx, idx) :: acc)
822     (status,[]) gl
823 ;;
824
825 let all_elements ctx cache =
826   let dummy = mk_cic_term ctx (NCic.Meta (0,(0, (NCic.Irl 0)))) in
827     try
828       let idx = List.assq ctx cache in
829       Ncic_termSet.elements 
830         (InvRelDiscriminationTree.retrieve_unifiables idx dummy)
831     with Not_found -> []
832
833 let add_to_th t c ty = 
834   let key_c = ctx_of t in
835   if not (List.mem_assq key_c c) then
836       (key_c ,InvRelDiscriminationTree.index 
837                InvRelDiscriminationTree.empty ty t ) :: c 
838   else
839     let rec replace = function
840       | [] -> []
841       | (x, idx) :: tl when x == key_c -> 
842           (x, InvRelDiscriminationTree.index idx ty t) :: tl
843       | x :: tl -> x :: replace tl
844     in 
845       replace c
846 ;;
847
848 let rm_from_th t c ty = 
849   let key_c = ctx_of t in
850   if not (List.mem_assq key_c c) then assert false
851   else
852     let rec replace = function
853       | [] -> []
854       | (x, idx) :: tl when x == key_c -> 
855           (x, InvRelDiscriminationTree.remove_index idx ty t) :: tl
856       | x :: tl -> x :: replace tl
857     in 
858       replace c
859 ;;
860
861 let pp_idx status idx =
862    InvRelDiscriminationTree.iter idx
863       (fun k set ->
864          noprint(lazy("K: " ^ NCicInverseRelIndexable.string_of_path k));
865          Ncic_termSet.iter 
866            (fun t -> debug_print(lazy("\t"^ppterm status t))) 
867            set)
868 ;;
869
870 let pp_th (status: #NTacStatus.pstatus) = 
871   List.iter 
872     (fun ctx, idx ->
873        noprint(lazy( "-----------------------------------------------"));
874        noprint(lazy( (status#ppcontext ~metasenv:[] ~subst:[] ctx)));
875        noprint(lazy( "||====>  "));
876        pp_idx status idx)
877 ;;
878
879 let search_in_th gty th = 
880   let c = ctx_of gty in
881   let rec aux acc = function
882    | [] -> (* Ncic_termSet.elements *) acc
883    | (_::tl) as k ->
884        try 
885          let idx = List.assoc(*q*) k th in
886          let acc = Ncic_termSet.union acc 
887            (InvRelDiscriminationTree.retrieve_unifiables idx gty)
888          in
889          aux acc tl
890        with Not_found -> aux acc tl
891   in
892     aux Ncic_termSet.empty c
893 ;;
894
895 type flags = {
896         do_types : bool; (* solve goals in Type *)
897         last : bool; (* last goal: take first solution only  *)
898         candidates: Ast.term list option;
899         local_candidates: bool;
900         maxwidth : int;
901         maxsize  : int;
902         maxdepth : int;
903 }
904
905 type cache =
906     {facts : th_cache; (* positive results *)
907      under_inspection : cic_term list * th_cache; (* to prune looping *)
908      failures : th_cache; (* to avoid repetitions *)
909      unit_eq : NCicParamod.state;
910      trace: Ast.term list
911     }
912
913 let add_to_trace status ~depth cache t =
914   match t with
915     | Ast.NRef _ -> 
916         debug_print ~depth (lazy ("Adding to trace: " ^ NotationPp.pp_term status t));
917         {cache with trace = t::cache.trace}
918     | Ast.NCic _  (* local candidate *)
919     | _  -> (*not an application *) cache 
920
921 let pptrace status tr = 
922   (lazy ("Proof Trace: " ^ (String.concat ";" 
923                               (List.map (NotationPp.pp_term status) tr))))
924 (* not used
925 let remove_from_trace cache t =
926   match t with
927     | Ast.NRef _ -> 
928         (match cache.trace with 
929            |  _::tl -> {cache with trace = tl}
930            | _ -> assert false)
931     | Ast.NCic _  (* local candidate *)
932     |  _  -> (*not an application *) cache *)
933
934 type sort = T | P
935 type goal = int * sort (* goal, depth, sort *)
936 type fail = goal * cic_term
937 type candidate = int * Ast.term (* unique candidate number, candidate *)
938
939 exception Gaveup of th_cache (* failure cache *)
940 exception Proved of NTacStatus.tac_status * Ast.term list
941
942 (* let close_failures _ c = c;; *)
943 (* let prunable _ _ _ = false;; *)
944 (* let cache_examine cache gty = `Notfound;; *)
945 (* let put_in_subst s _ _ _  = s;; *)
946 (* let add_to_cache_and_del_from_orlist_if_green_cut _ _ c _ _ o f _ = c, o, f, false ;; *)
947 (* let cache_add_underinspection c _ _ = c;; *)
948
949 let init_cache ?(facts=[]) ?(under_inspection=[],[])
950     ?(failures=[])
951     ?(unit_eq=NCicParamod.empty_state) 
952     ?(trace=[]) 
953     _ = 
954     {facts = facts;
955      failures = failures;
956      under_inspection = under_inspection;
957      unit_eq = unit_eq;
958      trace = trace}
959
960 let only signature _context candidate = true
961 (*
962         (* TASSI: nel trie ci mettiamo solo il body, non il ty *)
963   let candidate_ty = 
964    NCicTypeChecker.typeof ~subst:[] ~metasenv:[] [] candidate
965   in
966   let height = fast_height_of_term status candidate_ty in
967   let rc = signature >= height in
968   if rc = false then
969     noprint (lazy ("Filtro: " ^ status#ppterm ~context:[] ~subst:[]
970           ~metasenv:[] candidate ^ ": " ^ string_of_int height))
971   else 
972     noprint (lazy ("Tengo: " ^ status#ppterm ~context:[] ~subst:[]
973           ~metasenv:[] candidate ^ ": " ^ string_of_int height));
974
975   rc *)
976 ;; 
977
978 let candidate_no = ref 0;;
979
980 let openg_no status = List.length (head_goals status#stack)
981
982 let sort_candidates status ctx candidates =
983  let _,_,metasenv,subst,_ = status#obj in
984   let branch cand =
985     let status,ct = disambiguate status ctx ("",0,cand) `XTNone in
986     let status,t = term_of_cic_term status ct ctx in
987     let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
988     let res = branch status (mk_cic_term ctx ty) in
989     noprint (lazy ("branch factor for: " ^ (ppterm status ct) ^ " = " 
990                       ^ (string_of_int res)));
991       res
992   in 
993   let candidates = List.map (fun t -> branch t,t) candidates in
994   let candidates = 
995      List.sort (fun (a,_) (b,_) -> a - b) candidates in 
996   let candidates = List.map snd candidates in
997     noprint (lazy ("candidates =\n" ^ (String.concat "\n" 
998         (List.map (NotationPp.pp_term status) candidates))));
999     candidates
1000
1001 let sort_new_elems l =
1002   List.sort (fun (_,s1) (_,s2) -> openg_no s1 - openg_no s2) l
1003
1004 let rec stack_goals level gs = 
1005   if level = 0 then []
1006   else match gs with 
1007     | [] -> assert false
1008     | (g,_,_,_,_)::s -> 
1009         let is_open = function
1010           | (_,Continuationals.Stack.Open i) -> Some i
1011           | (_,Continuationals.Stack.Closed _) -> None
1012         in
1013           HExtlib.filter_map is_open g @ stack_goals (level-1) s
1014 ;;
1015
1016 let open_goals level status = stack_goals level status#stack
1017 ;;
1018
1019 let try_candidate ?(smart=0) flags depth status eq_cache ctx t =
1020   try
1021     let old_og_no = List.length (open_goals (depth+1) status) in
1022     debug_print ~depth (lazy ("try " ^ (string_of_int smart) ^ " : "
1023       ^ (NotationPp.pp_term status) t));
1024     let status = 
1025       if smart = 0 then NTactics.apply_tac ("",0,t) status
1026       else if smart = 1 then  
1027         smart_apply_auto ("",0,t) eq_cache status 
1028       else (* smart = 2: both *)
1029         try NTactics.apply_tac ("",0,t) status
1030         with Error _ -> 
1031           smart_apply_auto ("",0,t) eq_cache status 
1032     in
1033 (* FG: this optimization rules out some applications of
1034  * lift_bind (from contribs/lambda_delta/Basic_2/substitution/lift.ma)
1035  *
1036     (* we compare the expected branching with the actual one and
1037        prune the candidate when the latter is larger. The optimization
1038        is meant to rule out stange applications of flexible terms,
1039        such as the application of eq_f that always succeeds.  
1040        There is some gain but less than expected *)
1041     let og_no = List.length (open_goals (depth+1) status) in
1042     let status, cict = disambiguate status ctx ("",0,t) None in
1043     let status,ct = term_of_cic_term status cict ctx in
1044     let _,_,metasenv,subst,_ = status#obj in
1045     let ty = NCicTypeChecker.typeof status subst metasenv ctx ct in
1046     let res = branch status (mk_cic_term ctx ty) in
1047     let diff = og_no - old_og_no in
1048     debug_print (lazy ("expected branching: " ^ (string_of_int res)));
1049     debug_print (lazy ("actual: branching" ^ (string_of_int diff))); 
1050     (* some flexibility *)
1051     if og_no - old_og_no > res then 
1052       (debug_print (lazy ("branch factor for: " ^ (ppterm status cict) ^ " = " 
1053                     ^ (string_of_int res) ^ " vs. " ^ (string_of_int og_no)));
1054        debug_print ~depth (lazy "strange application"); None)
1055     else 
1056 *)      (incr candidate_no; Some ((!candidate_no,t),status))
1057    with Error (msg,exn) -> debug_print ~depth (lazy "failed"); None
1058 ;;
1059
1060 let sort_of status subst metasenv ctx t =
1061   let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
1062   let metasenv',ty = NCicUnification.fix_sorts status metasenv subst ty in
1063    assert (metasenv = metasenv');
1064    NCicTypeChecker.typeof status subst metasenv ctx ty
1065 ;;
1066   
1067 let type0= NUri.uri_of_string ("cic:/matita/pts/Type0.univ")
1068 ;;
1069
1070 let perforate_small status subst metasenv context t =
1071   let rec aux = function
1072     | NCic.Appl (hd::tl) ->
1073         let map t =
1074             let s = sort_of status subst metasenv context t in
1075             match s with
1076               | NCic.Sort(NCic.Type [`Type,u])
1077                   when u=type0 -> NCic.Meta (0,(0,NCic.Irl 0))
1078               | _ -> aux t
1079         in
1080           NCic.Appl (hd::List.map map tl)
1081     | t -> t
1082   in 
1083     aux t
1084 ;;
1085
1086 let get_cands retrieve_for diff empty gty weak_gty =
1087   let cands = retrieve_for gty in
1088     match weak_gty with
1089       | None -> cands, empty
1090       | Some weak_gty ->
1091           let more_cands =  retrieve_for weak_gty in
1092             cands, diff more_cands cands
1093 ;;
1094
1095 let is_a_needed_uri s d = 
1096   prerr_endline ("DEBUG: " ^ d ^ ": "^ s);
1097   s = "cic:/matita/basics/logic/eq.ind" ||
1098   s = "cic:/matita/basics/logic/sym_eq.con" ||
1099   s = "cic:/matita/basics/logic/trans_eq.con" ||
1100   s = "cic:/matita/basics/logic/eq_f3.con" ||
1101   s = "cic:/matita/basics/logic/eq_f2.con" ||
1102   s = "cic:/matita/basics/logic/eq_f.con"
1103
1104 let get_candidates ?(smart=true) ~pfailed depth flags status cache signature gty =
1105   let universe = status#auto_cache in
1106   let _,_,metasenv,subst,_ = status#obj in
1107   let context = ctx_of gty in
1108   let _, raw_gty = term_of_cic_term status gty context in
1109   let is_prod, is_eq =   
1110     let status, t = term_of_cic_term status gty context  in 
1111     let t = NCicReduction.whd status subst context t in
1112       match t with
1113         | NCic.Prod _ -> true, false
1114         | _ -> false, NCicParamod.is_equation status metasenv subst context t 
1115   in
1116   debug_print ~depth (lazy ("gty:" ^ NTacStatus.ppterm status gty));
1117   let is_eq = 
1118     NCicParamod.is_equation status metasenv subst context raw_gty 
1119   in
1120   let raw_weak_gty, weak_gty  =
1121     if smart then
1122       match raw_gty with
1123         | NCic.Appl _ 
1124         | NCic.Const _ 
1125         | NCic.Rel _ -> 
1126             let raw_weak = 
1127               perforate_small status subst metasenv context raw_gty in
1128             let weak = mk_cic_term context raw_weak in
1129             noprint ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1130               Some raw_weak, Some (weak)
1131         | _ -> None,None
1132     else None,None
1133   in
1134   (* we now compute global candidates *)
1135   let global_cands, smart_global_cands =
1136   let mapf s = 
1137     let to_ast = function 
1138       | NCic.Const r when true 
1139            (*is_relevant statistics r*) -> Some (Ast.NRef r)
1140    (* | NCic.Const _ -> None  *)
1141       | _ -> assert false in
1142         HExtlib.filter_map 
1143           to_ast (NDiscriminationTree.TermSet.elements s) in
1144     let g,l = 
1145       get_cands
1146         (NDiscriminationTree.DiscriminationTree.retrieve_unifiables universe)
1147         NDiscriminationTree.TermSet.diff 
1148         NDiscriminationTree.TermSet.empty
1149         raw_gty raw_weak_gty in
1150     mapf g, mapf l
1151   in 
1152   let global_cands,smart_global_cands = 
1153       if flags.local_candidates then global_cands,smart_global_cands
1154       else let filter = List.filter (function Ast.NRef NReference.Ref (uri,_) -> is_a_needed_uri
1155                                                                                    (NUri.string_of_uri
1156                                                                                       uri) "GLOBAL" | _ -> false) 
1157         in filter global_cands,filter smart_global_cands
1158   in
1159   (* we now compute local candidates *)
1160   let local_cands,smart_local_cands = 
1161     let mapf s = 
1162       let to_ast t =
1163         let _status, t = term_of_cic_term status t context 
1164         in Ast.NCic t in
1165         List.map to_ast (Ncic_termSet.elements s) in
1166     let g,l = 
1167       get_cands
1168         (fun ty -> search_in_th ty cache)
1169         Ncic_termSet.diff  Ncic_termSet.empty gty weak_gty in
1170       mapf g, mapf l
1171   in
1172   let local_cands,smart_local_cands = 
1173    if flags.local_candidates then local_cands,smart_local_cands
1174    else let filter = List.filter (function Ast.NRef NReference.Ref (uri,_) -> is_a_needed_uri
1175                                                                                 (NUri.string_of_uri
1176                                                                                    uri) "LOCAL" | _ -> false) 
1177      in filter local_cands,filter smart_local_cands
1178   in
1179   (* we now splits candidates in facts or not facts *)
1180   let test = is_a_fact_ast status subst metasenv context in
1181   let by,given_candidates =
1182     match flags.candidates with
1183     | Some l -> true, l
1184     | None -> false, [] in
1185 (* we compute candidates to be applied in normal mode, splitted in
1186      facts and not facts *)
1187   let candidates_facts,candidates_other =
1188     let gl1,gl2 = List.partition test global_cands in
1189     let ll1,ll2 = List.partition test local_cands in
1190     (* if the goal is an equation and paramodulation did not fail
1191      we avoid to apply unit equalities; refl is an
1192      exception since it prompts for convertibility *)
1193     let l1 = if is_eq && (not pfailed) 
1194       then [Ast.Ident("refl",None)] else gl1@ll1 in 
1195     let l2 = 
1196       (* if smart given candidates are applied in smart mode *)
1197       if by && smart then ll2
1198       else if by then given_candidates@ll2 
1199       else gl2@ll2
1200     in l1,l2
1201   in
1202   (* we now compute candidates to be applied in smart mode, splitted in
1203      facts and not facts *) 
1204   let smart_candidates_facts, smart_candidates_other =
1205     if is_prod || not(smart) then [],[] 
1206     else 
1207     let sgl1,sgl2 = List.partition test smart_global_cands in
1208     let sll1,sll2 = List.partition test smart_local_cands in
1209     let l1 = if is_eq then [] else sgl1@sll1 in
1210     let l2 = 
1211       if by && smart then given_candidates@sll2 
1212       else if by then sll2
1213       else sgl2@sll2
1214     in l1,l2
1215   in
1216   candidates_facts,
1217   smart_candidates_facts,
1218   sort_candidates status context (candidates_other),
1219   sort_candidates status context (smart_candidates_other)
1220 ;;
1221
1222 let applicative_case ~pfailed depth signature status flags gty cache =
1223   app_counter:= !app_counter+1; 
1224   let _,_,metasenv,subst,_ = status#obj in
1225   let context = ctx_of gty in
1226   let tcache = cache.facts in
1227   let is_prod, is_eq =   
1228     let status, t = term_of_cic_term status gty context  in 
1229     let t = NCicReduction.whd status subst context t in
1230       match t with
1231         | NCic.Prod _ -> true, false
1232         | _ -> false, NCicParamod.is_equation status metasenv subst context t 
1233   in
1234   debug_print ~depth (lazy (string_of_bool is_eq)); 
1235   (* new *)
1236   let candidates_facts, smart_candidates_facts, 
1237       candidates_other, smart_candidates_other = 
1238     get_candidates ~smart:true ~pfailed depth 
1239       flags status tcache signature gty 
1240   in
1241   let sm = if is_eq || is_prod then 0 else 2 in
1242   let sm1 = if flags.last then 2 else 0 in 
1243   let maxd = (depth + 1 = flags.maxdepth) in 
1244   let try_candidates only_one sm acc candidates =
1245     List.fold_left 
1246       (fun elems cand ->
1247          if (only_one && (elems <> [])) then elems 
1248          else
1249            match try_candidate (~smart:sm) 
1250              flags depth status cache.unit_eq context cand with
1251                | None -> elems
1252                | Some x -> x::elems)
1253       acc candidates
1254   in 
1255   (* if the goal is the last one we stop at the first fact *)
1256   let elems = try_candidates flags.last sm [] candidates_facts in
1257   (* now we add smart_facts *)
1258   let elems = try_candidates flags.last sm elems smart_candidates_facts in
1259   (* if we are at maxdepth and the goal is not a product we are done 
1260      similarly, if the goal is the last one and we already found a
1261      solution *)
1262   if (maxd && not(is_prod)) || (flags.last && elems<>[]) then elems
1263   else
1264     let elems = try_candidates false 2 elems candidates_other in
1265     debug_print ~depth (lazy ("not facts: try smart application"));
1266     try_candidates false 2 elems smart_candidates_other
1267 ;;
1268
1269 exception Found
1270 ;;
1271
1272 (* gty is supposed to be meta-closed *)
1273 let is_subsumed depth filter_depth status gty cache =
1274   if cache=[] then false else (
1275   debug_print ~depth (lazy("Subsuming " ^ (ppterm status gty))); 
1276   let n,h,metasenv,subst,obj = status#obj in
1277   let ctx = ctx_of gty in
1278   let _ , raw_gty = term_of_cic_term status gty ctx in
1279   let target = NCicSubstitution.lift status 1 raw_gty in 
1280   (* we compute candidates using the perforated type *)
1281   let weak_gty  =
1282     match target with
1283       | NCic.Appl _ 
1284       | NCic.Const _ 
1285       | NCic.Rel _ -> 
1286           let raw_weak = 
1287             perforate_small status subst metasenv ctx raw_gty in
1288           let weak = mk_cic_term ctx raw_weak in
1289           debug_print ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1290           Some (weak)
1291       | _ -> None
1292   in
1293   (* candidates must only be searched w.r.t the given context *)
1294   let candidates = 
1295     try
1296     let idx = List.assq ctx cache in
1297     match weak_gty with
1298       | Some weak ->
1299           Ncic_termSet.elements 
1300             (InvRelDiscriminationTree.retrieve_unifiables idx weak)
1301       |None -> []
1302     with Not_found -> []
1303   in
1304   (* this is a dirty trick: the first argument of an application is used
1305      to remember at which depth a goal failed *)
1306   let filter t = 
1307     let ctx = ctx_of t in 
1308     let _, src = term_of_cic_term status t ctx in 
1309     match src with 
1310      | NCic.Appl [NCic.Implicit (`Typeof d); t] 
1311        when d <= depth -> Some (mk_cic_term ctx t)
1312      | _ -> None in
1313   let candidates = 
1314     if filter_depth then HExtlib.filter_map filter candidates else candidates in  
1315   debug_print ~depth
1316     (lazy ("failure candidates: " ^ string_of_int (List.length candidates)));
1317     try
1318       List.iter
1319         (fun t ->
1320            let _ , source = term_of_cic_term status t ctx in
1321            let implication = 
1322              NCic.Prod("foo",source,target) in
1323            let metasenv,j,_,_ = 
1324              NCicMetaSubst.mk_meta  
1325                metasenv ctx ~with_type:implication `IsType in
1326            let status = status#set_obj (n,h,metasenv,subst,obj) in
1327            let status = status#set_stack [([1,Open j],[],[],`NoTag,[])] in 
1328            try
1329              let status = NTactics.intro_tac "foo" status in
1330              let status =
1331                NTactics.apply_tac ("",0,Ast.NCic (NCic.Rel 1)) status
1332              in 
1333                if (head_goals status#stack = []) then raise Found
1334                else ()
1335            with
1336              | Error _ -> ())
1337         candidates;false
1338     with Found -> debug_print ~depth (lazy "success");true)
1339 ;;
1340
1341 let rec guess_name name ctx = 
1342   if name = "_" then guess_name "auto" ctx else
1343   if not (List.mem_assoc name ctx) then name else
1344   guess_name (name^"'") ctx
1345 ;;
1346
1347 let is_prod status = 
1348   let _, ctx, gty = current_goal status in
1349   let status, gty = apply_subst status ctx gty in
1350   let _, raw_gty = term_of_cic_term status gty ctx in
1351   match raw_gty with
1352     | NCic.Prod (name,src,_) ->
1353         let status, src = whd status ~delta:0 ctx (mk_cic_term ctx src) in 
1354         (match snd (term_of_cic_term status src ctx) with
1355         | NCic.Const(NReference.Ref (_,NReference.Ind _) as r) 
1356         | NCic.Appl (NCic.Const(NReference.Ref (_,NReference.Ind _) as r)::_) ->
1357             let _,_,itys,_,_ = NCicEnvironment.get_checked_indtys status r in
1358             (match itys with
1359             (* | [_,_,_,[_;_]]  con nat va, ovviamente, in loop *)
1360             | [_,_,_,[_]] 
1361             | [_,_,_,[]] -> `Inductive (guess_name name ctx)         
1362             | _ -> `Some (guess_name name ctx))
1363         | _ -> `Some (guess_name name ctx))
1364     | _ -> `None
1365
1366 let intro ~depth status facts name =
1367   let status = NTactics.intro_tac name status in
1368   let _, ctx, ngty = current_goal status in
1369   let t = mk_cic_term ctx (NCic.Rel 1) in
1370   let status, keys = keys_of_term status t in
1371   let facts = List.fold_left (add_to_th t) facts keys in
1372     debug_print ~depth (lazy ("intro: "^ name));
1373   (* unprovability is not stable w.r.t introduction *)
1374   status, facts
1375 ;;
1376
1377 let rec intros_facts ~depth status facts =
1378   if List.length (head_goals status#stack) <> 1 then status, facts else
1379   match is_prod status with
1380     | `Inductive name 
1381     | `Some(name) ->
1382         let status,facts =
1383           intro ~depth status facts name
1384         in intros_facts ~depth status facts
1385 (*    | `Inductive name ->
1386           let status = NTactics.case1_tac name status in
1387           intros_facts ~depth status facts *)
1388     | _ -> status, facts
1389 ;; 
1390
1391 let intros ~depth status ?(use_given_only=false) cache =
1392     match is_prod status with
1393       | `Inductive _
1394       | `Some _ ->
1395           let trace = cache.trace in
1396           let status,facts =
1397             intros_facts ~depth status cache.facts 
1398           in 
1399           if head_goals status#stack = [] then 
1400             let status = NTactics.merge_tac status in
1401             [(0,Ast.Ident("__intros",None)),status], cache
1402           else
1403             (* we reindex the equation from scratch *)
1404             let unit_eq = index_local_equations status#eq_cache status ~flag:use_given_only in
1405             let status = NTactics.merge_tac status in
1406             [(0,Ast.Ident("__intros",None)),status], 
1407             init_cache ~facts ~unit_eq () ~trace
1408       | _ -> [],cache
1409 ;;
1410
1411 let reduce ~whd ~depth status g = 
1412   let n,h,metasenv,subst,o = status#obj in 
1413   let attr, ctx, ty = NCicUtils.lookup_meta g metasenv in
1414   let ty = NCicUntrusted.apply_subst status subst ctx ty in
1415   let ty' =
1416    (if whd then NCicReduction.whd else NCicTacReduction.normalize) status ~subst ctx ty
1417   in
1418   if ty = ty' then []
1419   else
1420     (debug_print ~depth 
1421       (lazy ("reduced to: "^ status#ppterm ctx subst metasenv ty'));
1422     let metasenv = 
1423       (g,(attr,ctx,ty'))::(List.filter (fun (i,_) -> i<>g) metasenv) 
1424     in
1425     let status = status#set_obj (n,h,metasenv,subst,o) in
1426     (* we merge to gain a depth level; the previous goal level should
1427        be empty *)
1428     let status = NTactics.merge_tac status in
1429     incr candidate_no;
1430     [(!candidate_no,Ast.Ident("__whd",None)),status])
1431 ;;
1432
1433 let is_meta status gty =
1434   let _, ty = term_of_cic_term status gty (ctx_of gty) in
1435   match ty with
1436   | NCic.Meta _ -> true
1437   | _ -> false 
1438 ;;
1439
1440 let do_something signature flags status g depth gty ?(use_given_only=false) cache =
1441   (* if the goal is meta we close it with I:True. This should work
1442     thanks to the toplogical sorting of goals. *)
1443   if is_meta status gty then
1444     let t = Ast.Ident("I",None) in
1445     debug_print (lazy ("using default term" ^ (NotationPp.pp_term status) t));
1446     let s = NTactics.apply_tac ("",0,t) status in
1447     [(0,t),s], cache
1448   else 
1449   let l0, cache = intros ~depth status cache ~use_given_only in
1450   if l0 <> [] then l0, cache
1451   else
1452   (* whd *)
1453   let l = reduce ~whd:true ~depth status g in
1454   (* if l <> [] then l,cache else *)
1455   (* backward aplications *)
1456   let l1 = 
1457     List.map 
1458       (fun s ->
1459          incr candidate_no;
1460          ((!candidate_no,Ast.Ident("__paramod",None)),s))
1461       (auto_eq_check cache.unit_eq status) 
1462   in
1463   let l2 = 
1464     if ((l1 <> []) && flags.last) then [] else
1465     applicative_case ~pfailed:(l1=[]) depth signature status flags gty cache 
1466   in
1467   (* statistics *)
1468   List.iter 
1469     (fun ((_,t),_) -> toref incr_nominations statistics t) l2;
1470   (* states in l1 have have an empty set of subgoals: no point to sort them *)
1471   debug_print ~depth 
1472     (lazy ("alternatives = " ^ (string_of_int (List.length (l1@l@l2)))));
1473     (* we order alternatives w.r.t the number of subgoals they open *)
1474     l1 @ (sort_new_elems l2) @ l, cache 
1475 ;;
1476
1477 let pp_goal = function
1478   | (_,Continuationals.Stack.Open i) 
1479   | (_,Continuationals.Stack.Closed i) -> string_of_int i 
1480 ;;
1481
1482 let pp_goals status l =
1483   String.concat ", " 
1484     (List.map 
1485        (fun i -> 
1486           let gty = get_goalty status i in
1487             NTacStatus.ppterm status gty)
1488        l)
1489 ;;
1490
1491 module M = 
1492   struct 
1493     type t = int
1494     let compare = Pervasives.compare
1495   end
1496 ;;
1497
1498 module MS = HTopoSort.Make(M)
1499 ;;
1500
1501 let sort_tac status =
1502   let gstatus = 
1503     match status#stack with
1504     | [] -> assert false
1505     | (goals, t, k, tag, p) :: s ->
1506         let g = head_goals status#stack in
1507         let sortedg = 
1508           (List.rev (MS.topological_sort g (deps status))) in
1509           noprint (lazy ("old g = " ^ 
1510             String.concat "," (List.map string_of_int g)));
1511           noprint (lazy ("sorted goals = " ^ 
1512             String.concat "," (List.map string_of_int sortedg)));
1513           let is_it i = function
1514             | (_,Continuationals.Stack.Open j ) 
1515             | (_,Continuationals.Stack.Closed j ) -> i = j
1516           in 
1517           let sorted_goals = 
1518             List.map (fun i -> List.find (is_it i) goals) sortedg
1519           in
1520             (sorted_goals, t, k, tag, p) :: s
1521   in
1522    status#set_stack gstatus
1523 ;;
1524   
1525 let clean_up_tac status =
1526   let gstatus = 
1527     match status#stack with
1528     | [] -> assert false
1529     | (g, t, k, tag, p) :: s ->
1530         let is_open = function
1531           | (_,Continuationals.Stack.Open _) -> true
1532           | (_,Continuationals.Stack.Closed _) -> false
1533         in
1534         let g' = List.filter is_open g in
1535           (g', t, k, tag, p) :: s
1536   in
1537    status#set_stack gstatus
1538 ;;
1539
1540 let focus_tac focus status =
1541   let gstatus = 
1542     match status#stack with
1543     | [] -> assert false
1544     | (g, t, k, tag) :: s ->
1545         let in_focus = function
1546           | (_,Continuationals.Stack.Open i) 
1547           | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1548         in
1549         let focus,others = List.partition in_focus g
1550         in
1551           (* we need to mark it as a BranchTag, otherwise cannot merge later *)
1552           (focus,[],[],`BranchTag) :: (others, t, k, tag) :: s
1553   in
1554    status#set_stack gstatus
1555 ;;
1556
1557 let deep_focus_tac level focus status =
1558   let in_focus = function
1559     | (_,Continuationals.Stack.Open i) 
1560     | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1561   in
1562   let rec slice level gs = 
1563     if level = 0 then [],[],gs else
1564       match gs with 
1565         | [] -> assert false
1566         | (g, t, k, tag,p) :: s ->
1567             let f,o,gs = slice (level-1) s in           
1568             let f1,o1 = List.partition in_focus g
1569             in
1570             (f1,[],[],`BranchTag, [])::f, (o1, t, k, tag, p)::o, gs
1571   in
1572   let gstatus = 
1573     let f,o,s = slice level status#stack in f@o@s
1574   in
1575    status#set_stack gstatus
1576 ;;
1577
1578 let move_to_side level status =
1579 match status#stack with
1580   | [] -> assert false
1581   | (g,_,_,_,_)::tl ->
1582       let is_open = function
1583           | (_,Continuationals.Stack.Open i) -> Some i
1584           | (_,Continuationals.Stack.Closed _) -> None
1585         in 
1586       let others = menv_closure status (stack_goals (level-1) tl) in
1587       List.for_all (fun i -> IntSet.mem i others) 
1588         (HExtlib.filter_map is_open g)
1589
1590 let top_cache ~depth top status ?(use_given_only=false) cache =
1591   if top then
1592     let unit_eq = index_local_equations status#eq_cache status ~flag:use_given_only in 
1593     {cache with unit_eq = unit_eq}
1594   else cache
1595
1596 let rec auto_clusters ?(top=false) flags signature cache depth ?(use_given_only=false) status : unit =
1597   debug_print ~depth (lazy ("entering auto clusters at depth " ^
1598                            (string_of_int depth)));
1599   debug_print ~depth (pptrace status cache.trace);
1600   (* ignore(Unix.select [] [] [] 0.01); *)
1601   let status = clean_up_tac status in
1602   let goals = head_goals status#stack in
1603   if goals = [] then 
1604     if depth = 0 then raise (Proved (status, cache.trace))
1605     else 
1606       let status = NTactics.merge_tac status in
1607         let cache =
1608         let l,tree = cache.under_inspection in
1609             match l with 
1610             | [] -> cache (* possible because of intros that cleans the cache *)
1611             | a::tl -> let tree = rm_from_th a tree a in
1612               {cache with under_inspection = tl,tree} 
1613         in 
1614          auto_clusters flags signature cache (depth-1) status ~use_given_only
1615   else if List.length goals < 2 then
1616     let cache = top_cache ~depth top status cache ~use_given_only in
1617     auto_main flags signature cache depth status ~use_given_only
1618   else
1619     let all_goals = open_goals (depth+1) status in
1620     debug_print ~depth (lazy ("goals = " ^ 
1621       String.concat "," (List.map string_of_int all_goals)));
1622     let classes = HExtlib.clusters (deps status) all_goals in
1623     (* if any of the classes exceed maxwidth we fail *)
1624     List.iter
1625       (fun gl ->
1626          if List.length gl > flags.maxwidth then 
1627            begin
1628              debug_print ~depth (lazy "FAIL GLOBAL WIDTH"); 
1629              HLog.warn (sprintf "global width (%u) exceeded: %u"
1630                flags.maxwidth (List.length gl));
1631              raise (Gaveup cache.failures)
1632            end else ()) classes;
1633     if List.length classes = 1 then
1634       let flags = 
1635         {flags with last = (List.length all_goals = 1)} in 
1636         (* no need to cluster *)
1637       let cache = top_cache ~depth top status cache ~use_given_only in
1638         auto_main flags signature cache depth status ~use_given_only
1639     else
1640       let classes = if top then List.rev classes else classes in
1641       debug_print ~depth
1642         (lazy 
1643            (String.concat "\n" 
1644            (List.map
1645              (fun l -> 
1646                ("cluster:" ^ String.concat "," (List.map string_of_int l)))
1647            classes)));
1648       (* we now process each cluster *)
1649       let status,cache,b = 
1650         List.fold_left
1651           (fun (status,cache,b) gl ->
1652              let flags = 
1653                {flags with last = (List.length gl = 1)} in 
1654              let lold = List.length status#stack in 
1655               debug_print ~depth (lazy ("stack length = " ^ 
1656                         (string_of_int lold)));
1657              let fstatus = deep_focus_tac (depth+1) gl status in
1658              let cache = top_cache ~depth top fstatus cache ~use_given_only in
1659              try 
1660                debug_print ~depth (lazy ("focusing on" ^ 
1661                               String.concat "," (List.map string_of_int gl)));
1662                auto_main flags signature cache depth fstatus ~use_given_only; assert false
1663              with 
1664                | Proved(status,trace) -> 
1665                    let status = NTactics.merge_tac status in
1666                    let cache = {cache with trace = trace} in
1667                    let lnew = List.length status#stack in 
1668                      assert (lold = lnew);
1669                    (status,cache,true)
1670                | Gaveup failures when top ->
1671                    let cache = {cache with failures = failures} in
1672                    (status,cache,b)
1673           )
1674           (status,cache,false) classes
1675       in
1676       let rec final_merge n s =
1677         if n = 0 then s else final_merge (n-1) (NTactics.merge_tac s)
1678       in let status = final_merge depth status 
1679       in if b then raise (Proved(status,cache.trace)) else raise (Gaveup cache.failures)
1680
1681 and
1682         
1683 (* BRAND NEW VERSION *)         
1684 auto_main flags signature cache depth status ?(use_given_only=false): unit=
1685   debug_print ~depth (lazy "entering auto main");
1686   debug_print ~depth (pptrace status cache.trace);
1687   debug_print ~depth (lazy ("stack length = " ^ 
1688                         (string_of_int (List.length status#stack))));
1689   (* ignore(Unix.select [] [] [] 0.01); *)
1690   let status = sort_tac (clean_up_tac status) in
1691   let goals = head_goals status#stack in
1692   match goals with
1693     | [] when depth = 0 -> raise (Proved (status,cache.trace))
1694     | []  -> 
1695         let status = NTactics.merge_tac status in
1696         let cache =
1697           let l,tree = cache.under_inspection in
1698             match l with 
1699               | [] -> cache (* possible because of intros that cleans the cache *)
1700               | a::tl -> let tree = rm_from_th a tree a in
1701                   {cache with under_inspection = tl,tree} 
1702         in 
1703           auto_clusters flags signature cache (depth-1) status ~use_given_only
1704     | orig::_ ->
1705         if depth > 0 && move_to_side depth status
1706         then 
1707           let status = NTactics.merge_tac status in
1708           let cache =
1709             let l,tree = cache.under_inspection in
1710               match l with 
1711                 | [] -> cache (* possible because of intros that cleans the cache*)
1712                 | a::tl -> let tree = rm_from_th a tree a in
1713                     {cache with under_inspection = tl,tree} 
1714           in 
1715             auto_clusters flags signature cache (depth-1) status ~use_given_only
1716         else
1717         let ng = List.length goals in
1718         (* moved inside auto_clusters *)
1719         if ng > flags.maxwidth then begin 
1720           debug_print ~depth (lazy "FAIL LOCAL WIDTH");
1721           HLog.warn (sprintf "local width (%u) exceeded: %u"
1722              flags.maxwidth ng);
1723           raise (Gaveup cache.failures)
1724         end else if depth = flags.maxdepth then
1725           raise (Gaveup cache.failures)
1726         else 
1727         let status = NTactics.branch_tac ~force:true status in
1728         let g,gctx, gty = current_goal status in
1729         let ctx,ty = close status g in
1730         let closegty = mk_cic_term ctx ty in
1731         let status, gty = apply_subst status gctx gty in
1732         debug_print ~depth (lazy("Attacking goal " ^ 
1733           string_of_int g ^ " : "^ppterm status gty));
1734         debug_print ~depth (lazy ("current failures: " ^ 
1735           string_of_int (List.length (all_elements ctx cache.failures))));
1736         let is_eq =
1737            let _,_,metasenv,subst,_ = status#obj in
1738            NCicParamod.is_equation status metasenv subst ctx ty in
1739         (* if the goal is an equality we artificially raise its depth up to
1740            flags.maxdepth - 1 *)
1741         if (not flags.last && is_eq && (depth < (flags.maxdepth -2))) then
1742         (* for efficiency reasons, in this case we severely cripple the
1743            search depth *)
1744           (debug_print ~depth (lazy ("RAISING DEPTH TO " ^ string_of_int (depth+1)));
1745            auto_main flags signature cache (depth+1) status ~use_given_only)
1746         (* check for loops *)
1747         else if is_subsumed depth false status closegty (snd cache.under_inspection) then 
1748           (debug_print ~depth (lazy "SUBSUMED");
1749            raise (Gaveup cache.failures))
1750         (* check for failures *)
1751         else if is_subsumed depth true status closegty cache.failures then 
1752           (debug_print ~depth (lazy "ALREADY MET");
1753            raise (Gaveup cache.failures))
1754         else
1755         let new_sig = height_of_goal g status in
1756         if new_sig < signature then 
1757           (debug_print  ~depth (lazy ("news = " ^ (string_of_int new_sig)));
1758            debug_print  ~depth (lazy ("olds = " ^ (string_of_int signature)))); 
1759         let alternatives, cache = 
1760           do_something signature flags status g depth gty cache ~use_given_only in
1761         let loop_cache =
1762           if flags.last then
1763             let l,tree = cache.under_inspection in
1764             let l,tree = closegty::l, add_to_th closegty tree closegty in
1765             {cache with under_inspection = l,tree}
1766           else cache in 
1767         let failures =
1768           List.fold_left  
1769           (fun allfailures ((_,t),status) ->
1770              debug_print ~depth 
1771                (lazy ("(re)considering goal " ^ 
1772                        (string_of_int g) ^" : "^ppterm status gty)); 
1773              debug_print (~depth:depth) 
1774                (lazy ("Case: " ^ NotationPp.pp_term status t));
1775              let depth,cache =
1776                if t=Ast.Ident("__whd",None) || 
1777                   t=Ast.Ident("__intros",None) 
1778                then depth, cache 
1779                else depth+1,loop_cache in 
1780              let cache = add_to_trace status ~depth cache t in
1781              let cache = {cache with failures = allfailures} in
1782              try
1783                auto_clusters flags signature cache depth status ~use_given_only;
1784                assert false;
1785              with Gaveup fail ->
1786                debug_print ~depth (lazy "Failed");
1787                fail)
1788           cache.failures alternatives in
1789         let failures =
1790           if flags.last then 
1791             let newfail =
1792               let dty = NCic.Appl [NCic.Implicit (`Typeof depth); ty] in
1793               mk_cic_term ctx dty 
1794             in 
1795             (*prerr_endline ("FAILURE : " ^ ppterm status gty);*)
1796             add_to_th newfail failures closegty
1797           else failures in
1798         debug_print ~depth (lazy "no more candidates");
1799         raise (Gaveup failures)
1800 ;;
1801
1802 let int name l def = 
1803   try int_of_string (List.assoc name l)
1804   with Failure _ | Not_found -> def
1805 ;;
1806
1807 module AstSet = Set.Make(struct type t = Ast.term let compare = compare end)
1808
1809 let cleanup_trace s trace =
1810   (* removing duplicates *)
1811   let trace_set = 
1812     List.fold_left 
1813       (fun acc t -> AstSet.add t acc)
1814       AstSet.empty trace in
1815   let trace = AstSet.elements trace_set
1816     (* filtering facts *)
1817   in List.filter 
1818        (fun t -> 
1819           match t with
1820             | Ast.NRef (NReference.Ref (u,_)) -> not (is_a_fact_obj s u)
1821             | _ -> false) trace
1822 ;;
1823
1824 (*CSC: TODO
1825
1826 - auto_params e' una high tactic che prende in input i parametri e poi li
1827   processa nel contesto vuoto calcolando i candidate
1828
1829 - astrarla su una auto_params' che prende in input gia' i candidate e un
1830   nuovo parametro per evitare il calcolo dei candidate locali che invece
1831   diventano vuoti (ovvero: non usare automaticamente tutte le ipotesi, bensi'
1832   nessuna)
1833
1834 - reimplementi la auto_params chiamando la auto_params' con il flag a 
1835   false e il vecchio codice per andare da parametri a candiddati
1836   OVVERO: usa tutti le ipotesi locali + candidati globali
1837
1838 - crei un nuovo entry point lowtac che calcola i candidati usando il contesto
1839   corrente e poi fa exec della auto_params' con i candidati e il flag a true
1840   OVVERO: usa solo candidati globali che comprendono ipotesi locali
1841 *)
1842
1843 type auto_params = NTacStatus.tactic_term list option * (string * string) list
1844
1845 (*let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =*)
1846 let auto_tac' candidates ~local_candidates ?(use_given_only=false) flags ?(trace_ref=ref []) status =
1847   let oldstatus = status in
1848   let status = (status:> NTacStatus.tac_status) in
1849   let goals = head_goals status#stack in
1850   let status, facts = mk_th_cache status goals in
1851 (*  let unit_eq = index_local_equations status#eq_cache status in *)
1852   let cache = init_cache ~facts () in 
1853 (*   pp_th status facts; *)
1854 (*
1855   NDiscriminationTree.DiscriminationTree.iter status#auto_cache (fun p t -> 
1856     debug_print (lazy(
1857       NDiscriminationTree.NCicIndexable.string_of_path p ^ " |--> " ^
1858       String.concat "\n    " (List.map (
1859       status#ppterm ~metasenv:[] ~context:[] ~subst:[])
1860         (NDiscriminationTree.TermSet.elements t))
1861       )));
1862 *)
1863   let depth = int "depth" flags 3 in 
1864   let size  = int "size" flags 10 in 
1865   let width = int "width" flags 4 (* (3+List.length goals)*) in 
1866   (* XXX fix sort *)
1867 (*   let goals = List.map (fun i -> (i,P)) goals in *)
1868   let signature = height_of_goals status in 
1869   let flags = { 
1870           last = true;
1871           candidates = candidates;
1872           local_candidates = local_candidates;
1873           maxwidth = width;
1874           maxsize = size;
1875           maxdepth = depth;
1876           do_types = false; 
1877   } in
1878   let initial_time = Unix.gettimeofday() in
1879   app_counter:= 0;
1880   let rec up_to x y =
1881     if x > y then
1882       (debug_print(lazy
1883         ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1884        debug_print(lazy
1885         ("Applicative nodes:"^string_of_int !app_counter)); 
1886        raise (Error (lazy "auto gave up", None)))
1887     else
1888       let _ = debug_print (lazy("\n\nRound "^string_of_int x^"\n")) in
1889       let flags = { flags with maxdepth = x } 
1890       in 
1891         try auto_clusters (~top:true) flags signature cache 0 status ~use_given_only;assert false 
1892 (*
1893         try auto_main flags signature cache 0 status;assert false
1894 *)
1895         with
1896           | Gaveup _ -> up_to (x+1) y
1897           | Proved (s,trace) -> 
1898               debug_print (lazy ("proved at depth " ^ string_of_int x));
1899               List.iter (toref incr_uses statistics) trace;
1900               let trace = cleanup_trace s trace in
1901               let _ = debug_print (pptrace status trace) in
1902               let stack = 
1903                 match s#stack with
1904                   | (g,t,k,f,p) :: rest -> (filter_open g,t,k,f,p):: rest
1905                   | _ -> assert false
1906               in
1907               let s = s#set_stack stack in
1908                 trace_ref := trace;
1909                 oldstatus#set_status s 
1910   in
1911   let s = up_to depth depth in
1912     debug_print (print_stat status statistics);
1913     debug_print(lazy
1914         ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1915     debug_print(lazy
1916         ("Applicative nodes:"^string_of_int !app_counter));
1917     s
1918 ;;
1919
1920 let candidates_from_ctx univ ctx status =
1921     match univ with
1922     | None -> None 
1923     | Some l -> 
1924         let to_Ast t =
1925             (* FG: `XTSort here? *)                    
1926             let status, res = disambiguate status ctx t `XTNone in 
1927             let _,res = term_of_cic_term status res (ctx_of res) 
1928             in Ast.NCic res 
1929         in Some (List.map to_Ast l) 
1930
1931 let auto_lowtac ~params:(univ,flags as params) status goal =
1932     let gty = get_goalty status goal in
1933     let ctx = ctx_of gty in
1934     let candidates = candidates_from_ctx univ ctx status in 
1935     auto_tac' candidates ~local_candidates:false ~use_given_only:true flags ~trace_ref:(ref [])
1936
1937 let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =
1938     let candidates = candidates_from_ctx univ [] status in
1939     auto_tac' candidates ~local_candidates:true ~use_given_only:false flags ~trace_ref status
1940
1941 let auto_tac ~params:(_,flags as params) ?trace_ref =
1942   if List.mem_assoc "demod" flags then 
1943     demod_tac ~params 
1944   else if List.mem_assoc "paramod" flags then 
1945     paramod_tac ~params 
1946   else if List.mem_assoc "fast_paramod" flags then 
1947     fast_eq_check_tac ~params  
1948   else auto_tac ~params ?trace_ref
1949 ;;