]> matita.cs.unibo.it Git - helm.git/blob - matita/components/ng_tactics/nnAuto.ml
4873481ed9b7df99b93f06170483cad0e9563f6d
[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 get_candidates ?(smart=true) ~pfailed depth flags status cache signature gty =
1096   let universe = status#auto_cache in
1097   let _,_,metasenv,subst,_ = status#obj in
1098   let context = ctx_of gty in
1099   let _, raw_gty = term_of_cic_term status gty context in
1100   let is_prod, is_eq =   
1101     let status, t = term_of_cic_term status gty context  in 
1102     let t = NCicReduction.whd status subst context t in
1103       match t with
1104         | NCic.Prod _ -> true, false
1105         | _ -> false, NCicParamod.is_equation status metasenv subst context t 
1106   in
1107   debug_print ~depth (lazy ("gty:" ^ NTacStatus.ppterm status gty));
1108   let is_eq = 
1109     NCicParamod.is_equation status metasenv subst context raw_gty 
1110   in
1111   let raw_weak_gty, weak_gty  =
1112     if smart then
1113       match raw_gty with
1114         | NCic.Appl _ 
1115         | NCic.Const _ 
1116         | NCic.Rel _ -> 
1117             let raw_weak = 
1118               perforate_small status subst metasenv context raw_gty in
1119             let weak = mk_cic_term context raw_weak in
1120             noprint ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1121               Some raw_weak, Some (weak)
1122         | _ -> None,None
1123     else None,None
1124   in
1125   (* we now compute global candidates *)
1126   let global_cands, smart_global_cands =
1127    if flags.local_candidates then
1128     let mapf s = 
1129       let to_ast = function 
1130         | NCic.Const r when true 
1131              (*is_relevant statistics r*) -> Some (Ast.NRef r)
1132      (* | NCic.Const _ -> None  *)
1133         | _ -> assert false in
1134           HExtlib.filter_map 
1135             to_ast (NDiscriminationTree.TermSet.elements s) in
1136       let g,l = 
1137         get_cands
1138           (NDiscriminationTree.DiscriminationTree.retrieve_unifiables universe)
1139           NDiscriminationTree.TermSet.diff 
1140           NDiscriminationTree.TermSet.empty
1141           raw_gty raw_weak_gty in
1142       mapf g, mapf l
1143     else [],[] in
1144   (* we now compute local candidates *)
1145   let local_cands,smart_local_cands = 
1146    if flags.local_candidates then
1147     let mapf s = 
1148       let to_ast t =
1149         let _status, t = term_of_cic_term status t context 
1150         in Ast.NCic t in
1151         List.map to_ast (Ncic_termSet.elements s) in
1152     let g,l = 
1153       get_cands
1154         (fun ty -> search_in_th ty cache)
1155         Ncic_termSet.diff  Ncic_termSet.empty gty weak_gty in
1156       mapf g, mapf l
1157    else [],[] in
1158   (* we now splits candidates in facts or not facts *)
1159   let test = is_a_fact_ast status subst metasenv context in
1160   let by,given_candidates =
1161     match flags.candidates with
1162     | Some l -> true, l
1163     | None -> false, [] in
1164 (* we compute candidates to be applied in normal mode, splitted in
1165      facts and not facts *)
1166   let candidates_facts,candidates_other =
1167     let gl1,gl2 = List.partition test global_cands in
1168     let ll1,ll2 = List.partition test local_cands in
1169     (* if the goal is an equation and paramodulation did not fail
1170      we avoid to apply unit equalities; refl is an
1171      exception since it prompts for convertibility *)
1172     let l1 = if is_eq && (not pfailed) 
1173       then [Ast.Ident("refl",None)] else gl1@ll1 in 
1174     let l2 = 
1175       (* if smart given candidates are applied in smart mode *)
1176       if by && smart then ll2
1177       else if by then given_candidates@ll2 
1178       else gl2@ll2
1179     in l1,l2
1180   in
1181   (* we now compute candidates to be applied in smart mode, splitted in
1182      facts and not facts *) 
1183   let smart_candidates_facts, smart_candidates_other =
1184     if is_prod || not(smart) then [],[] 
1185     else 
1186     let sgl1,sgl2 = List.partition test smart_global_cands in
1187     let sll1,sll2 = List.partition test smart_local_cands in
1188     let l1 = if is_eq then [] else sgl1@sll1 in
1189     let l2 = 
1190       if by && smart then given_candidates@sll2 
1191       else if by then sll2
1192       else sgl2@sll2
1193     in l1,l2
1194   in
1195   candidates_facts,
1196   smart_candidates_facts,
1197   sort_candidates status context (candidates_other),
1198   sort_candidates status context (smart_candidates_other)
1199 ;;
1200
1201 let applicative_case ~pfailed depth signature status flags gty cache =
1202   app_counter:= !app_counter+1; 
1203   let _,_,metasenv,subst,_ = status#obj in
1204   let context = ctx_of gty in
1205   let tcache = cache.facts in
1206   let is_prod, is_eq =   
1207     let status, t = term_of_cic_term status gty context  in 
1208     let t = NCicReduction.whd status subst context t in
1209       match t with
1210         | NCic.Prod _ -> true, false
1211         | _ -> false, NCicParamod.is_equation status metasenv subst context t 
1212   in
1213   debug_print ~depth (lazy (string_of_bool is_eq)); 
1214   (* new *)
1215   let candidates_facts, smart_candidates_facts, 
1216       candidates_other, smart_candidates_other = 
1217     get_candidates ~smart:true ~pfailed depth 
1218       flags status tcache signature gty 
1219   in
1220   let sm = if is_eq || is_prod then 0 else 2 in
1221   let sm1 = if flags.last then 2 else 0 in 
1222   let maxd = (depth + 1 = flags.maxdepth) in 
1223   let try_candidates only_one sm acc candidates =
1224     List.fold_left 
1225       (fun elems cand ->
1226          if (only_one && (elems <> [])) then elems 
1227          else
1228            match try_candidate (~smart:sm) 
1229              flags depth status cache.unit_eq context cand with
1230                | None -> elems
1231                | Some x -> x::elems)
1232       acc candidates
1233   in 
1234   (* if the goal is the last one we stop at the first fact *)
1235   let elems = try_candidates flags.last sm [] candidates_facts in
1236   (* now we add smart_facts *)
1237   let elems = try_candidates flags.last sm elems smart_candidates_facts in
1238   (* if we are at maxdepth and the goal is not a product we are done 
1239      similarly, if the goal is the last one and we already found a
1240      solution *)
1241   if (maxd && not(is_prod)) || (flags.last && elems<>[]) then elems
1242   else
1243     let elems = try_candidates false 2 elems candidates_other in
1244     debug_print ~depth (lazy ("not facts: try smart application"));
1245     try_candidates false 2 elems smart_candidates_other
1246 ;;
1247
1248 exception Found
1249 ;;
1250
1251 (* gty is supposed to be meta-closed *)
1252 let is_subsumed depth filter_depth status gty cache =
1253   if cache=[] then false else (
1254   debug_print ~depth (lazy("Subsuming " ^ (ppterm status gty))); 
1255   let n,h,metasenv,subst,obj = status#obj in
1256   let ctx = ctx_of gty in
1257   let _ , raw_gty = term_of_cic_term status gty ctx in
1258   let target = NCicSubstitution.lift status 1 raw_gty in 
1259   (* we compute candidates using the perforated type *)
1260   let weak_gty  =
1261     match target with
1262       | NCic.Appl _ 
1263       | NCic.Const _ 
1264       | NCic.Rel _ -> 
1265           let raw_weak = 
1266             perforate_small status subst metasenv ctx raw_gty in
1267           let weak = mk_cic_term ctx raw_weak in
1268           debug_print ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1269           Some (weak)
1270       | _ -> None
1271   in
1272   (* candidates must only be searched w.r.t the given context *)
1273   let candidates = 
1274     try
1275     let idx = List.assq ctx cache in
1276     match weak_gty with
1277       | Some weak ->
1278           Ncic_termSet.elements 
1279             (InvRelDiscriminationTree.retrieve_unifiables idx weak)
1280       |None -> []
1281     with Not_found -> []
1282   in
1283   (* this is a dirty trick: the first argument of an application is used
1284      to remember at which depth a goal failed *)
1285   let filter t = 
1286     let ctx = ctx_of t in 
1287     let _, src = term_of_cic_term status t ctx in 
1288     match src with 
1289      | NCic.Appl [NCic.Implicit (`Typeof d); t] 
1290        when d <= depth -> Some (mk_cic_term ctx t)
1291      | _ -> None in
1292   let candidates = 
1293     if filter_depth then HExtlib.filter_map filter candidates else candidates in  
1294   debug_print ~depth
1295     (lazy ("failure candidates: " ^ string_of_int (List.length candidates)));
1296     try
1297       List.iter
1298         (fun t ->
1299            let _ , source = term_of_cic_term status t ctx in
1300            let implication = 
1301              NCic.Prod("foo",source,target) in
1302            let metasenv,j,_,_ = 
1303              NCicMetaSubst.mk_meta  
1304                metasenv ctx ~with_type:implication `IsType in
1305            let status = status#set_obj (n,h,metasenv,subst,obj) in
1306            let status = status#set_stack [([1,Open j],[],[],`NoTag)] in 
1307            try
1308              let status = NTactics.intro_tac "foo" status in
1309              let status =
1310                NTactics.apply_tac ("",0,Ast.NCic (NCic.Rel 1)) status
1311              in 
1312                if (head_goals status#stack = []) then raise Found
1313                else ()
1314            with
1315              | Error _ -> ())
1316         candidates;false
1317     with Found -> debug_print ~depth (lazy "success");true)
1318 ;;
1319
1320 let rec guess_name name ctx = 
1321   if name = "_" then guess_name "auto" ctx else
1322   if not (List.mem_assoc name ctx) then name else
1323   guess_name (name^"'") ctx
1324 ;;
1325
1326 let is_prod status = 
1327   let _, ctx, gty = current_goal status in
1328   let status, gty = apply_subst status ctx gty in
1329   let _, raw_gty = term_of_cic_term status gty ctx in
1330   match raw_gty with
1331     | NCic.Prod (name,src,_) ->
1332         let status, src = whd status ~delta:0 ctx (mk_cic_term ctx src) in 
1333         (match snd (term_of_cic_term status src ctx) with
1334         | NCic.Const(NReference.Ref (_,NReference.Ind _) as r) 
1335         | NCic.Appl (NCic.Const(NReference.Ref (_,NReference.Ind _) as r)::_) ->
1336             let _,_,itys,_,_ = NCicEnvironment.get_checked_indtys status r in
1337             (match itys with
1338             (* | [_,_,_,[_;_]]  con nat va, ovviamente, in loop *)
1339             | [_,_,_,[_]] 
1340             | [_,_,_,[]] -> `Inductive (guess_name name ctx)         
1341             | _ -> `Some (guess_name name ctx))
1342         | _ -> `Some (guess_name name ctx))
1343     | _ -> `None
1344
1345 let intro ~depth status facts name =
1346   let status = NTactics.intro_tac name status in
1347   let _, ctx, ngty = current_goal status in
1348   let t = mk_cic_term ctx (NCic.Rel 1) in
1349   let status, keys = keys_of_term status t in
1350   let facts = List.fold_left (add_to_th t) facts keys in
1351     debug_print ~depth (lazy ("intro: "^ name));
1352   (* unprovability is not stable w.r.t introduction *)
1353   status, facts
1354 ;;
1355
1356 let rec intros_facts ~depth status facts =
1357   if List.length (head_goals status#stack) <> 1 then status, facts else
1358   match is_prod status with
1359     | `Inductive name 
1360     | `Some(name) ->
1361         let status,facts =
1362           intro ~depth status facts name
1363         in intros_facts ~depth status facts
1364 (*    | `Inductive name ->
1365           let status = NTactics.case1_tac name status in
1366           intros_facts ~depth status facts *)
1367     | _ -> status, facts
1368 ;; 
1369
1370 let intros ~depth status ?(use_given_only=false) cache =
1371     match is_prod status with
1372       | `Inductive _
1373       | `Some _ ->
1374           let trace = cache.trace in
1375           let status,facts =
1376             intros_facts ~depth status cache.facts 
1377           in 
1378           if head_goals status#stack = [] then 
1379             let status = NTactics.merge_tac status in
1380             [(0,Ast.Ident("__intros",None)),status], cache
1381           else
1382             (* we reindex the equation from scratch *)
1383             let unit_eq = index_local_equations status#eq_cache status ~flag:use_given_only in
1384             let status = NTactics.merge_tac status in
1385             [(0,Ast.Ident("__intros",None)),status], 
1386             init_cache ~facts ~unit_eq () ~trace
1387       | _ -> [],cache
1388 ;;
1389
1390 let reduce ~whd ~depth status g = 
1391   let n,h,metasenv,subst,o = status#obj in 
1392   let attr, ctx, ty = NCicUtils.lookup_meta g metasenv in
1393   let ty = NCicUntrusted.apply_subst status subst ctx ty in
1394   let ty' =
1395    (if whd then NCicReduction.whd else NCicTacReduction.normalize) status ~subst ctx ty
1396   in
1397   if ty = ty' then []
1398   else
1399     (debug_print ~depth 
1400       (lazy ("reduced to: "^ status#ppterm ctx subst metasenv ty'));
1401     let metasenv = 
1402       (g,(attr,ctx,ty'))::(List.filter (fun (i,_) -> i<>g) metasenv) 
1403     in
1404     let status = status#set_obj (n,h,metasenv,subst,o) in
1405     (* we merge to gain a depth level; the previous goal level should
1406        be empty *)
1407     let status = NTactics.merge_tac status in
1408     incr candidate_no;
1409     [(!candidate_no,Ast.Ident("__whd",None)),status])
1410 ;;
1411
1412 let is_meta status gty =
1413   let _, ty = term_of_cic_term status gty (ctx_of gty) in
1414   match ty with
1415   | NCic.Meta _ -> true
1416   | _ -> false 
1417 ;;
1418
1419 let do_something signature flags status g depth gty ?(use_given_only=false) cache =
1420   (* if the goal is meta we close it with I:True. This should work
1421     thanks to the toplogical sorting of goals. *)
1422   if is_meta status gty then
1423     let t = Ast.Ident("I",None) in
1424     debug_print (lazy ("using default term" ^ (NotationPp.pp_term status) t));
1425     let s = NTactics.apply_tac ("",0,t) status in
1426     [(0,t),s], cache
1427   else 
1428   let l0, cache = intros ~depth status cache ~use_given_only in
1429   if l0 <> [] then l0, cache
1430   else
1431   (* whd *)
1432   let l = reduce ~whd:true ~depth status g in
1433   (* if l <> [] then l,cache else *)
1434   (* backward aplications *)
1435   let l1 = 
1436     List.map 
1437       (fun s ->
1438          incr candidate_no;
1439          ((!candidate_no,Ast.Ident("__paramod",None)),s))
1440       (auto_eq_check cache.unit_eq status) 
1441   in
1442   let l2 = 
1443     if ((l1 <> []) && flags.last) then [] else
1444     applicative_case ~pfailed:(l1=[]) depth signature status flags gty cache 
1445   in
1446   (* statistics *)
1447   List.iter 
1448     (fun ((_,t),_) -> toref incr_nominations statistics t) l2;
1449   (* states in l1 have have an empty set of subgoals: no point to sort them *)
1450   debug_print ~depth 
1451     (lazy ("alternatives = " ^ (string_of_int (List.length (l1@l@l2)))));
1452     (* we order alternatives w.r.t the number of subgoals they open *)
1453     l1 @ (sort_new_elems l2) @ l, cache 
1454 ;;
1455
1456 let pp_goal = function
1457   | (_,Continuationals.Stack.Open i) 
1458   | (_,Continuationals.Stack.Closed i) -> string_of_int i 
1459 ;;
1460
1461 let pp_goals status l =
1462   String.concat ", " 
1463     (List.map 
1464        (fun i -> 
1465           let gty = get_goalty status i in
1466             NTacStatus.ppterm status gty)
1467        l)
1468 ;;
1469
1470 module M = 
1471   struct 
1472     type t = int
1473     let compare = Pervasives.compare
1474   end
1475 ;;
1476
1477 module MS = HTopoSort.Make(M)
1478 ;;
1479
1480 let sort_tac status =
1481   let gstatus = 
1482     match status#stack with
1483     | [] -> assert false
1484     | (goals, t, k, tag) :: s ->
1485         let g = head_goals status#stack in
1486         let sortedg = 
1487           (List.rev (MS.topological_sort g (deps status))) in
1488           noprint (lazy ("old g = " ^ 
1489             String.concat "," (List.map string_of_int g)));
1490           noprint (lazy ("sorted goals = " ^ 
1491             String.concat "," (List.map string_of_int sortedg)));
1492           let is_it i = function
1493             | (_,Continuationals.Stack.Open j ) 
1494             | (_,Continuationals.Stack.Closed j ) -> i = j
1495           in 
1496           let sorted_goals = 
1497             List.map (fun i -> List.find (is_it i) goals) sortedg
1498           in
1499             (sorted_goals, t, k, tag) :: s
1500   in
1501    status#set_stack gstatus
1502 ;;
1503   
1504 let clean_up_tac status =
1505   let gstatus = 
1506     match status#stack with
1507     | [] -> assert false
1508     | (g, t, k, tag) :: s ->
1509         let is_open = function
1510           | (_,Continuationals.Stack.Open _) -> true
1511           | (_,Continuationals.Stack.Closed _) -> false
1512         in
1513         let g' = List.filter is_open g in
1514           (g', t, k, tag) :: s
1515   in
1516    status#set_stack gstatus
1517 ;;
1518
1519 let focus_tac focus status =
1520   let gstatus = 
1521     match status#stack with
1522     | [] -> assert false
1523     | (g, t, k, tag) :: s ->
1524         let in_focus = function
1525           | (_,Continuationals.Stack.Open i) 
1526           | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1527         in
1528         let focus,others = List.partition in_focus g
1529         in
1530           (* we need to mark it as a BranchTag, otherwise cannot merge later *)
1531           (focus,[],[],`BranchTag) :: (others, t, k, tag) :: s
1532   in
1533    status#set_stack gstatus
1534 ;;
1535
1536 let deep_focus_tac level focus status =
1537   let in_focus = function
1538     | (_,Continuationals.Stack.Open i) 
1539     | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1540   in
1541   let rec slice level gs = 
1542     if level = 0 then [],[],gs else
1543       match gs with 
1544         | [] -> assert false
1545         | (g, t, k, tag) :: s ->
1546             let f,o,gs = slice (level-1) s in           
1547             let f1,o1 = List.partition in_focus g
1548             in
1549             (f1,[],[],`BranchTag)::f, (o1, t, k, tag)::o, gs
1550   in
1551   let gstatus = 
1552     let f,o,s = slice level status#stack in f@o@s
1553   in
1554    status#set_stack gstatus
1555 ;;
1556
1557 let move_to_side level status =
1558 match status#stack with
1559   | [] -> assert false
1560   | (g,_,_,_)::tl ->
1561       let is_open = function
1562           | (_,Continuationals.Stack.Open i) -> Some i
1563           | (_,Continuationals.Stack.Closed _) -> None
1564         in 
1565       let others = menv_closure status (stack_goals (level-1) tl) in
1566       List.for_all (fun i -> IntSet.mem i others) 
1567         (HExtlib.filter_map is_open g)
1568
1569 let top_cache ~depth top status ?(use_given_only=false) cache =
1570   if top then
1571     let unit_eq = index_local_equations status#eq_cache status ~flag:use_given_only in 
1572     {cache with unit_eq = unit_eq}
1573   else cache
1574
1575 let rec auto_clusters ?(top=false) flags signature cache depth ?(use_given_only=false) status : unit =
1576   debug_print ~depth (lazy ("entering auto clusters at depth " ^
1577                            (string_of_int depth)));
1578   debug_print ~depth (pptrace status cache.trace);
1579   (* ignore(Unix.select [] [] [] 0.01); *)
1580   let status = clean_up_tac status in
1581   let goals = head_goals status#stack in
1582   if goals = [] then 
1583     if depth = 0 then raise (Proved (status, cache.trace))
1584     else 
1585       let status = NTactics.merge_tac status in
1586         let cache =
1587         let l,tree = cache.under_inspection in
1588             match l with 
1589             | [] -> cache (* possible because of intros that cleans the cache *)
1590             | a::tl -> let tree = rm_from_th a tree a in
1591               {cache with under_inspection = tl,tree} 
1592         in 
1593          auto_clusters flags signature cache (depth-1) status ~use_given_only
1594   else if List.length goals < 2 then
1595     let cache = top_cache ~depth top status cache ~use_given_only in
1596     auto_main flags signature cache depth status ~use_given_only
1597   else
1598     let all_goals = open_goals (depth+1) status in
1599     debug_print ~depth (lazy ("goals = " ^ 
1600       String.concat "," (List.map string_of_int all_goals)));
1601     let classes = HExtlib.clusters (deps status) all_goals in
1602     (* if any of the classes exceed maxwidth we fail *)
1603     List.iter
1604       (fun gl ->
1605          if List.length gl > flags.maxwidth then 
1606            begin
1607              debug_print ~depth (lazy "FAIL GLOBAL WIDTH"); 
1608              HLog.warn (sprintf "global width (%u) exceeded: %u"
1609                flags.maxwidth (List.length gl));
1610              raise (Gaveup cache.failures)
1611            end else ()) classes;
1612     if List.length classes = 1 then
1613       let flags = 
1614         {flags with last = (List.length all_goals = 1)} in 
1615         (* no need to cluster *)
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 classes = if top then List.rev classes else classes in
1620       debug_print ~depth
1621         (lazy 
1622            (String.concat "\n" 
1623            (List.map
1624              (fun l -> 
1625                ("cluster:" ^ String.concat "," (List.map string_of_int l)))
1626            classes)));
1627       (* we now process each cluster *)
1628       let status,cache,b = 
1629         List.fold_left
1630           (fun (status,cache,b) gl ->
1631              let flags = 
1632                {flags with last = (List.length gl = 1)} in 
1633              let lold = List.length status#stack in 
1634               debug_print ~depth (lazy ("stack length = " ^ 
1635                         (string_of_int lold)));
1636              let fstatus = deep_focus_tac (depth+1) gl status in
1637              let cache = top_cache ~depth top fstatus cache ~use_given_only in
1638              try 
1639                debug_print ~depth (lazy ("focusing on" ^ 
1640                               String.concat "," (List.map string_of_int gl)));
1641                auto_main flags signature cache depth fstatus ~use_given_only; assert false
1642              with 
1643                | Proved(status,trace) -> 
1644                    let status = NTactics.merge_tac status in
1645                    let cache = {cache with trace = trace} in
1646                    let lnew = List.length status#stack in 
1647                      assert (lold = lnew);
1648                    (status,cache,true)
1649                | Gaveup failures when top ->
1650                    let cache = {cache with failures = failures} in
1651                    (status,cache,b)
1652           )
1653           (status,cache,false) classes
1654       in
1655       let rec final_merge n s =
1656         if n = 0 then s else final_merge (n-1) (NTactics.merge_tac s)
1657       in let status = final_merge depth status 
1658       in if b then raise (Proved(status,cache.trace)) else raise (Gaveup cache.failures)
1659
1660 and
1661         
1662 (* BRAND NEW VERSION *)         
1663 auto_main flags signature cache depth status ?(use_given_only=false): unit=
1664   debug_print ~depth (lazy "entering auto main");
1665   debug_print ~depth (pptrace status cache.trace);
1666   debug_print ~depth (lazy ("stack length = " ^ 
1667                         (string_of_int (List.length status#stack))));
1668   (* ignore(Unix.select [] [] [] 0.01); *)
1669   let status = sort_tac (clean_up_tac status) in
1670   let goals = head_goals status#stack in
1671   match goals with
1672     | [] when depth = 0 -> raise (Proved (status,cache.trace))
1673     | []  -> 
1674         let status = NTactics.merge_tac status in
1675         let cache =
1676           let l,tree = cache.under_inspection in
1677             match l with 
1678               | [] -> cache (* possible because of intros that cleans the cache *)
1679               | a::tl -> let tree = rm_from_th a tree a in
1680                   {cache with under_inspection = tl,tree} 
1681         in 
1682           auto_clusters flags signature cache (depth-1) status ~use_given_only
1683     | orig::_ ->
1684         if depth > 0 && move_to_side depth status
1685         then 
1686           let status = NTactics.merge_tac status in
1687           let cache =
1688             let l,tree = cache.under_inspection in
1689               match l with 
1690                 | [] -> cache (* possible because of intros that cleans the cache*)
1691                 | a::tl -> let tree = rm_from_th a tree a in
1692                     {cache with under_inspection = tl,tree} 
1693           in 
1694             auto_clusters flags signature cache (depth-1) status ~use_given_only
1695         else
1696         let ng = List.length goals in
1697         (* moved inside auto_clusters *)
1698         if ng > flags.maxwidth then begin 
1699           debug_print ~depth (lazy "FAIL LOCAL WIDTH");
1700           HLog.warn (sprintf "local width (%u) exceeded: %u"
1701              flags.maxwidth ng);
1702           raise (Gaveup cache.failures)
1703         end else if depth = flags.maxdepth then
1704           raise (Gaveup cache.failures)
1705         else 
1706         let status = NTactics.branch_tac ~force:true status in
1707         let g,gctx, gty = current_goal status in
1708         let ctx,ty = close status g in
1709         let closegty = mk_cic_term ctx ty in
1710         let status, gty = apply_subst status gctx gty in
1711         debug_print ~depth (lazy("Attacking goal " ^ 
1712           string_of_int g ^ " : "^ppterm status gty));
1713         debug_print ~depth (lazy ("current failures: " ^ 
1714           string_of_int (List.length (all_elements ctx cache.failures))));
1715         let is_eq =
1716            let _,_,metasenv,subst,_ = status#obj in
1717            NCicParamod.is_equation status metasenv subst ctx ty in
1718         (* if the goal is an equality we artificially raise its depth up to
1719            flags.maxdepth - 1 *)
1720         if (not flags.last && is_eq && (depth < (flags.maxdepth -2))) then
1721         (* for efficiency reasons, in this case we severely cripple the
1722            search depth *)
1723           (debug_print ~depth (lazy ("RAISING DEPTH TO " ^ string_of_int (depth+1)));
1724            auto_main flags signature cache (depth+1) status ~use_given_only)
1725         (* check for loops *)
1726         else if is_subsumed depth false status closegty (snd cache.under_inspection) then 
1727           (debug_print ~depth (lazy "SUBSUMED");
1728            raise (Gaveup cache.failures))
1729         (* check for failures *)
1730         else if is_subsumed depth true status closegty cache.failures then 
1731           (debug_print ~depth (lazy "ALREADY MET");
1732            raise (Gaveup cache.failures))
1733         else
1734         let new_sig = height_of_goal g status in
1735         if new_sig < signature then 
1736           (debug_print  ~depth (lazy ("news = " ^ (string_of_int new_sig)));
1737            debug_print  ~depth (lazy ("olds = " ^ (string_of_int signature)))); 
1738         let alternatives, cache = 
1739           do_something signature flags status g depth gty cache ~use_given_only in
1740         let loop_cache =
1741           if flags.last then
1742             let l,tree = cache.under_inspection in
1743             let l,tree = closegty::l, add_to_th closegty tree closegty in
1744             {cache with under_inspection = l,tree}
1745           else cache in 
1746         let failures =
1747           List.fold_left  
1748           (fun allfailures ((_,t),status) ->
1749              debug_print ~depth 
1750                (lazy ("(re)considering goal " ^ 
1751                        (string_of_int g) ^" : "^ppterm status gty)); 
1752              debug_print (~depth:depth) 
1753                (lazy ("Case: " ^ NotationPp.pp_term status t));
1754              let depth,cache =
1755                if t=Ast.Ident("__whd",None) || 
1756                   t=Ast.Ident("__intros",None) 
1757                then depth, cache 
1758                else depth+1,loop_cache in 
1759              let cache = add_to_trace status ~depth cache t in
1760              let cache = {cache with failures = allfailures} in
1761              try
1762                auto_clusters flags signature cache depth status ~use_given_only;
1763                assert false;
1764              with Gaveup fail ->
1765                debug_print ~depth (lazy "Failed");
1766                fail)
1767           cache.failures alternatives in
1768         let failures =
1769           if flags.last then 
1770             let newfail =
1771               let dty = NCic.Appl [NCic.Implicit (`Typeof depth); ty] in
1772               mk_cic_term ctx dty 
1773             in 
1774             (*prerr_endline ("FAILURE : " ^ ppterm status gty);*)
1775             add_to_th newfail failures closegty
1776           else failures in
1777         debug_print ~depth (lazy "no more candidates");
1778         raise (Gaveup failures)
1779 ;;
1780
1781 let int name l def = 
1782   try int_of_string (List.assoc name l)
1783   with Failure _ | Not_found -> def
1784 ;;
1785
1786 module AstSet = Set.Make(struct type t = Ast.term let compare = compare end)
1787
1788 let cleanup_trace s trace =
1789   (* removing duplicates *)
1790   let trace_set = 
1791     List.fold_left 
1792       (fun acc t -> AstSet.add t acc)
1793       AstSet.empty trace in
1794   let trace = AstSet.elements trace_set
1795     (* filtering facts *)
1796   in List.filter 
1797        (fun t -> 
1798           match t with
1799             | Ast.NRef (NReference.Ref (u,_)) -> not (is_a_fact_obj s u)
1800             | _ -> false) trace
1801 ;;
1802
1803 (*CSC: TODO
1804
1805 - auto_params e' una high tactic che prende in input i parametri e poi li
1806   processa nel contesto vuoto calcolando i candidate
1807
1808 - astrarla su una auto_params' che prende in input gia' i candidate e un
1809   nuovo parametro per evitare il calcolo dei candidate locali che invece
1810   diventano vuoti (ovvero: non usare automaticamente tutte le ipotesi, bensi'
1811   nessuna)
1812
1813 - reimplementi la auto_params chiamando la auto_params' con il flag a 
1814   false e il vecchio codice per andare da parametri a candiddati
1815   OVVERO: usa tutti le ipotesi locali + candidati globali
1816
1817 - crei un nuovo entry point lowtac che calcola i candidati usando il contesto
1818   corrente e poi fa exec della auto_params' con i candidati e il flag a true
1819   OVVERO: usa solo candidati globali che comprendono ipotesi locali
1820 *)
1821
1822 type auto_params = NTacStatus.tactic_term list option * (string * string) list
1823
1824 (*let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =*)
1825 let auto_tac' candidates ~local_candidates ?(use_given_only=false) flags ?(trace_ref=ref []) status =
1826   let oldstatus = status in
1827   let status = (status:> NTacStatus.tac_status) in
1828   let goals = head_goals status#stack in
1829   let status, facts = mk_th_cache status goals in
1830 (*  let unit_eq = index_local_equations status#eq_cache status in *)
1831   let cache = init_cache ~facts () in 
1832 (*   pp_th status facts; *)
1833 (*
1834   NDiscriminationTree.DiscriminationTree.iter status#auto_cache (fun p t -> 
1835     debug_print (lazy(
1836       NDiscriminationTree.NCicIndexable.string_of_path p ^ " |--> " ^
1837       String.concat "\n    " (List.map (
1838       status#ppterm ~metasenv:[] ~context:[] ~subst:[])
1839         (NDiscriminationTree.TermSet.elements t))
1840       )));
1841 *)
1842   let depth = int "depth" flags 3 in 
1843   let size  = int "size" flags 10 in 
1844   let width = int "width" flags 4 (* (3+List.length goals)*) in 
1845   (* XXX fix sort *)
1846 (*   let goals = List.map (fun i -> (i,P)) goals in *)
1847   let signature = height_of_goals status in 
1848   let flags = { 
1849           last = true;
1850           candidates = candidates;
1851           local_candidates = local_candidates;
1852           maxwidth = width;
1853           maxsize = size;
1854           maxdepth = depth;
1855           do_types = false; 
1856   } in
1857   let initial_time = Unix.gettimeofday() in
1858   app_counter:= 0;
1859   let rec up_to x y =
1860     if x > y then
1861       (debug_print(lazy
1862         ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1863        debug_print(lazy
1864         ("Applicative nodes:"^string_of_int !app_counter)); 
1865        raise (Error (lazy "auto gave up", None)))
1866     else
1867       let _ = debug_print (lazy("\n\nRound "^string_of_int x^"\n")) in
1868       let flags = { flags with maxdepth = x } 
1869       in 
1870         try auto_clusters (~top:true) flags signature cache 0 status ~use_given_only;assert false 
1871 (*
1872         try auto_main flags signature cache 0 status;assert false
1873 *)
1874         with
1875           | Gaveup _ -> up_to (x+1) y
1876           | Proved (s,trace) -> 
1877               debug_print (lazy ("proved at depth " ^ string_of_int x));
1878               List.iter (toref incr_uses statistics) trace;
1879               let trace = cleanup_trace s trace in
1880               let _ = debug_print (pptrace status trace) in
1881               let stack = 
1882                 match s#stack with
1883                   | (g,t,k,f) :: rest -> (filter_open g,t,k,f):: rest
1884                   | _ -> assert false
1885               in
1886               let s = s#set_stack stack in
1887                 trace_ref := trace;
1888                 oldstatus#set_status s 
1889   in
1890   let s = up_to depth depth in
1891     debug_print (print_stat status statistics);
1892     debug_print(lazy
1893         ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1894     debug_print(lazy
1895         ("Applicative nodes:"^string_of_int !app_counter));
1896     s
1897 ;;
1898
1899 let candidates_from_ctx univ ctx status =
1900     match univ with
1901     | None -> None 
1902     | Some l -> 
1903         let to_Ast t =
1904             (* FG: `XTSort here? *)                    
1905             let status, res = disambiguate status ctx t `XTNone in 
1906             let _,res = term_of_cic_term status res (ctx_of res) 
1907             in Ast.NCic res 
1908         in Some (List.map to_Ast l) 
1909
1910 let auto_lowtac ~params:(univ,flags as params) status goal =
1911     let gty = get_goalty status goal in
1912     let ctx = ctx_of gty in
1913     let candidates = candidates_from_ctx univ ctx status in 
1914     auto_tac' candidates ~local_candidates:true ~use_given_only:false flags ~trace_ref:(ref [])
1915
1916 let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =
1917     let candidates = candidates_from_ctx univ [] status in
1918     auto_tac' candidates ~local_candidates:true ~use_given_only:false flags ~trace_ref status
1919
1920 let auto_tac ~params:(_,flags as params) ?trace_ref =
1921   if List.mem_assoc "demod" flags then 
1922     demod_tac ~params 
1923   else if List.mem_assoc "paramod" flags then 
1924     paramod_tac ~params 
1925   else if List.mem_assoc "fast_paramod" flags then 
1926     fast_eq_check_tac ~params  
1927   else auto_tac ~params ?trace_ref
1928 ;;