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.
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_______________________________________________________________ *)
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
19 open Continuationals.Stack
21 module Ast = NotationPt
23 (* ======================= statistics ========================= *)
25 let app_counter = ref 0
28 type t = NReference.reference
30 let compare = Pervasives.compare
31 let hash = Hashtbl.hash
34 module RefHash = Hashtbl.Make(RHT);;
37 nominations : int ref;
41 let statistics: info RefHash.t = RefHash.create 503
43 let incr_nominations tbl item =
45 let v = RefHash.find tbl item in incr v.nominations
47 RefHash.add tbl item {nominations = ref 1; uses = ref 0}
49 let incr_uses tbl item =
51 let v = RefHash.find tbl item in incr v.uses
52 with Not_found -> assert false
58 | Ast.NCic _ (* local candidate *)
61 let is_relevant tbl item =
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
67 with Not_found -> true
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
76 Filename.chop_extension
77 (Filename.basename (NReference.string_of_reference r))
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))
87 (* ======================= utility functions ========================= *)
88 module IntSet = Set.Make(struct type t = int let compare = compare end)
90 let get_sgoalty status g =
91 let _,_,metasenv,subst,_ = status#obj in
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
98 NTacStatus.mk_cic_term ctx ty
99 with NCicUtils.Meta_not_found _ as exn -> fail ~exn (lazy "get_sgoalty")
103 let gty = get_sgoalty status g in
104 metas_of_term status gty
107 let menv_closure status gl =
108 let rec closure acc = function
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
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 *)
126 let _, m = term_of_cic_term status m (ctx_of m) in
128 | NCic.Meta(i,_) -> IntSet.add i acc
132 (* IntSet.subset menv clos *)
133 IntSet.cardinal(IntSet.diff menv clos)
135 let is_a_fact status ty = branch status ty = 0
137 let is_a_fact_obj s uri =
138 let obj = NCicEnvironment.get_checked_obj s uri in
140 | (_,_,[],[],NCic.Constant(_,_,_,ty,_)) ->
141 is_a_fact s (mk_cic_term [] ty)
142 (* aggiungere i costruttori *)
145 let is_a_fact_ast status subst metasenv ctx cand =
147 (lazy ("------- checking " ^ NotationPp.pp_term status cand));
148 let status, t = disambiguate status ctx ("",0,cand) None 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)
153 let current_goal ?(single_goal=true) status =
154 let open_goals = head_goals status#stack in
156 then assert (List.length open_goals = 1)
157 else assert (List.length open_goals >= 1);
158 let open_goal = List.hd open_goals in
159 let gty = get_goalty status open_goal in
160 let ctx = ctx_of gty in
163 let height_of_ref status (NReference.Ref (uri, x)) =
168 | NReference.CoFix _ ->
169 let _,height,_,_,_ = NCicEnvironment.get_checked_obj status uri in
171 | NReference.Def h -> h
172 | NReference.Fix (_,_,h) -> h
175 (*************************** height functions ********************************)
176 let fast_height_of_term status t =
180 NCic.Meta (_,(_,NCic.Ctx l)) -> List.iter aux l
184 | NCic.Implicit _ -> assert false
187 prerr_endline (status#ppterm ~metasenv:[] ~subst:[]
188 ~context:[] t ^ ":" ^ string_of_int (height_of_ref status nref));
190 h := max !h (height_of_ref status nref)
191 | NCic.Prod (_,t1,t2)
192 | NCic.Lambda (_,t1,t2) -> aux t1; aux t2
193 | NCic.LetIn (_,s,ty,t) -> aux s; aux ty; aux t
194 | NCic.Appl l -> List.iter aux l
195 | NCic.Match (_,outty,t,pl) -> aux outty; aux t; List.iter aux pl
200 let height_of_goal g status =
201 let ty = get_goalty status g in
202 let context = ctx_of ty in
203 let _, ty = term_of_cic_term status ty (ctx_of ty) in
204 let h = ref (fast_height_of_term status ty) in
207 | _, NCic.Decl ty -> h := max !h (fast_height_of_term status ty)
208 | _, NCic.Def (bo,ty) ->
209 h := max !h (fast_height_of_term status ty);
210 h := max !h (fast_height_of_term status bo);
216 let height_of_goals status =
217 let open_goals = head_goals status#stack in
218 assert (List.length open_goals > 0);
222 h := max !h (height_of_goal open_goal status))
224 noprint (lazy ("altezza sequente: " ^ string_of_int !h));
228 (* =============================== paramod =========================== *)
229 let solve f status eq_cache goal =
232 if fast then NCicParamod.fast_eq_check
233 else NCicParamod.paramod in
235 let n,h,metasenv,subst,o = status#obj in
236 let gname, ctx, gty = List.assoc goal metasenv in
237 let gty = NCicUntrusted.apply_subst status subst ctx gty in
238 let build_status (pt, _, metasenv, subst) =
240 noprint (lazy ("refining: "^(status#ppterm ctx subst metasenv pt)));
241 let stamp = Unix.gettimeofday () in
242 let metasenv, subst, pt, pty =
243 (* NCicRefiner.typeof status
244 (* (status#set_coerc_db NCicCoercion.empty_db) *)
245 metasenv subst ctx pt None in
246 debug_print (lazy ("refined: "^(status#ppterm ctx subst metasenv pt)));
247 noprint (lazy ("synt: "^(status#ppterm ctx subst metasenv pty)));
248 let metasenv, subst =
249 NCicUnification.unify status metasenv subst ctx gty pty *)
251 (status#set_coerc_db NCicCoercion.empty_db)
252 metasenv subst ctx pt (Some gty)
254 noprint (lazy (Printf.sprintf "Refined in %fs"
255 (Unix.gettimeofday() -. stamp)));
256 let status = status#set_obj (n,h,metasenv,subst,o) in
257 let metasenv = List.filter (fun j,_ -> j <> goal) metasenv in
258 let subst = (goal,(gname,ctx,pt,pty)) :: subst in
259 Some (status#set_obj (n,h,metasenv,subst,o))
261 NCicRefiner.RefineFailure msg
262 | NCicRefiner.Uncertain msg ->
263 debug_print (lazy ("WARNING: refining in fast_eq_check failed\n" ^
264 snd (Lazy.force msg) ^
265 "\n in the environment\n" ^
266 status#ppmetasenv subst metasenv)); None
267 | NCicRefiner.AssertFailure msg ->
268 debug_print (lazy ("WARNING: refining in fast_eq_check failed" ^
270 "\n in the environment\n" ^
271 status#ppmetasenv subst metasenv)); None
274 HExtlib.filter_map build_status
275 (f status metasenv subst ctx eq_cache (NCic.Rel ~-1,gty))
278 let fast_eq_check eq_cache status (goal:int) =
279 match solve NCicParamod.fast_eq_check status eq_cache goal with
280 | [] -> raise (Error (lazy "no proof found",None))
284 let dist_fast_eq_check eq_cache s =
285 NTactics.distribute_tac (fast_eq_check eq_cache) s
288 let auto_eq_check eq_cache status =
290 let s = dist_fast_eq_check eq_cache status in
293 | Error _ -> debug_print (lazy ("no paramod proof found"));[]
296 let index_local_equations eq_cache status =
297 noprint (lazy "indexing equations");
298 let open_goals = head_goals status#stack in
299 let open_goal = List.hd open_goals in
300 let ngty = get_goalty status open_goal in
301 let _,_,metasenv,subst,_ = status#obj in
302 let ctx = apply_subst_context ~fix_projections:true status (ctx_of ngty) in
307 let t = NCic.Rel !c in
309 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
310 if is_a_fact status (mk_cic_term ctx ty) then
311 (noprint(lazy("eq indexing " ^ (status#ppterm ctx subst metasenv ty)));
312 NCicParamod.forward_infer_step status metasenv subst ctx eq_cache t ty)
314 (noprint (lazy ("not a fact: " ^ (status#ppterm ctx subst metasenv ty)));
317 | NCicTypeChecker.TypeCheckerFailure _
318 | NCicTypeChecker.AssertFailure _ -> eq_cache)
322 let fast_eq_check_tac ~params s =
323 let unit_eq = index_local_equations s#eq_cache s in
324 dist_fast_eq_check unit_eq s
327 let paramod eq_cache status goal =
328 match solve NCicParamod.paramod status eq_cache goal with
329 | [] -> raise (Error (lazy "no proof found",None))
333 let paramod_tac ~params s =
334 let unit_eq = index_local_equations s#eq_cache s in
335 NTactics.distribute_tac (paramod unit_eq) s
338 let demod eq_cache status goal =
339 match solve NCicParamod.demod status eq_cache goal with
340 | [] -> raise (Error (lazy "no progress",None))
344 let demod_tac ~params s =
345 let unit_eq = index_local_equations s#eq_cache s in
346 NTactics.distribute_tac (demod unit_eq) s
350 let fast_eq_check_tac_all ~params eq_cache status =
351 let g,_,_ = current_goal status in
352 let allstates = fast_eq_check_all status eq_cache g in
353 let pseudo_low_tac s _ _ = s in
354 let pseudo_low_tactics =
355 List.map pseudo_low_tac allstates
357 List.map (fun f -> NTactics.distribute_tac f status) pseudo_low_tactics
362 let demod status eq_cache goal =
363 let n,h,metasenv,subst,o = status#obj in
364 let gname, ctx, gty = List.assoc goal metasenv in
365 let gty = NCicUntrusted.apply_subst subst ctx gty in
367 let demod_tac ~params s =
368 let unit_eq = index_local_equations s#eq_cache s in
369 dist_fast_eq_check unit_eq s
372 (*************** subsumption ****************)
374 let close_wrt_context status =
378 | name, NCic.Decl t -> NCic.Prod(name,t,ty)
379 | name, NCic.Def(bo, _) -> NCicSubstitution.subst status bo ty)
382 let args_for_context ?(k=1) ctx =
385 (fun (n,l) ctx_entry ->
387 | name, NCic.Decl t -> n+1,NCic.Rel(n)::l
388 | name, NCic.Def(bo, _) -> n+1,l)
392 let constant_for_meta status ctx ty i =
393 let name = "cic:/foo"^(string_of_int i)^".con" in
394 let uri = NUri.uri_of_string name in
395 let ty = close_wrt_context status ty ctx in
396 (* prerr_endline (status#ppterm [] [] [] ty); *)
397 let attr = (`Generated,`Definition,`Local) in
398 let obj = NCic.Constant([],name,None,ty,attr) in
399 (* Constant of relevance * string * term option * term * c_attr *)
403 let refresh metasenv =
405 (fun (metasenv,subst) (i,(iattr,ctx,ty)) ->
406 let ikind = NCicUntrusted.kind_of_meta iattr in
407 let metasenv,j,instance,ty =
408 NCicMetaSubst.mk_meta ~attrs:iattr
409 metasenv ctx ~with_type:ty ikind in
410 let s_entry = i,(iattr, ctx, instance, ty) in
411 let metasenv = List.filter (fun x,_ -> i <> x) metasenv in
412 metasenv,s_entry::subst)
413 (metasenv,[]) metasenv
415 (* close metasenv returns a ground instance of all the metas in the
416 metasenv, insantiatied with axioms, and the list of these axioms *)
417 let close_metasenv status metasenv subst =
419 let metasenv = NCicUntrusted.apply_subst_metasenv subst metasenv in
421 let metasenv = NCicUntrusted.sort_metasenv status subst metasenv in
423 (fun (subst,objs) (i,(iattr,ctx,ty)) ->
424 let ty = NCicUntrusted.apply_subst status subst ctx ty in
426 NCicUntrusted.apply_subst_context status ~fix_projections:true
428 let (uri,_,_,_,obj) as okind =
429 constant_for_meta status ctx ty i in
431 NCicEnvironment.check_and_add_obj status okind;
432 let iref = NReference.reference_of_spec uri NReference.Decl in
434 let args = args_for_context ctx in
435 if args = [] then NCic.Const iref
436 else NCic.Appl(NCic.Const iref::args)
438 (* prerr_endline (status#ppterm ctx [] [] iterm); *)
439 let s_entry = i, ([], ctx, iterm, ty)
440 in s_entry::subst,okind::objs
441 with _ -> assert false)
445 let ground_instances status gl =
446 let _,_,metasenv,subst,_ = status#obj in
447 let subset = menv_closure status gl in
448 let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
450 let submenv = metasenv in
452 let subst, objs = close_metasenv status submenv subst in
456 let (_, ctx, t, _) = List.assoc i subst in
457 noprint (lazy (status#ppterm ctx [] [] t));
459 (fun (uri,_,_,_,_) as obj ->
460 NCicEnvironment.invalidate_item status (`Obj (uri, obj)))
465 Not_found -> assert false
469 let replace_meta status i args target =
470 let rec aux k = function
471 (* TODO: local context *)
472 | NCic.Meta (j,lc) when i = j ->
476 List.map (NCicSubstitution.subst_meta status lc) args in
477 NCic.Appl(NCic.Rel k::args))
478 | NCic.Meta (j,lc) as m ->
485 aux k (NCicSubstitution.lift status n t)) l))))
486 | t -> NCicUtils.map status (fun _ k -> k+1) k aux t
491 let close_wrt_metasenv status subst =
493 (fun ty (i,(iattr,ctx,mty)) ->
494 let mty = NCicUntrusted.apply_subst status subst ctx mty in
496 NCicUntrusted.apply_subst_context status ~fix_projections:true
498 let cty = close_wrt_context status mty ctx in
499 let name = "foo"^(string_of_int i) in
500 let ty = NCicSubstitution.lift status 1 ty in
501 let args = args_for_context ~k:1 ctx in
502 (* prerr_endline (status#ppterm ctx [] [] iterm); *)
503 let ty = replace_meta status i args ty
505 NCic.Prod(name,cty,ty))
509 let _,_,metasenv,subst,_ = status#obj in
510 let subset = menv_closure status [g] in
511 let subset = IntSet.remove g subset in
512 let elems = IntSet.elements subset in
513 let _, ctx, ty = NCicUtils.lookup_meta g metasenv in
514 let ty = NCicUntrusted.apply_subst status subst ctx ty in
515 noprint (lazy ("metas in " ^ (status#ppterm ctx [] metasenv ty)));
516 noprint (lazy (String.concat ", " (List.map string_of_int elems)));
517 let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
518 let submenv = List.rev (NCicUntrusted.sort_metasenv status subst submenv) in
520 let submenv = metasenv in
522 let ty = close_wrt_metasenv status subst ty submenv in
523 noprint (lazy (status#ppterm ctx [] [] ty));
527 (****************** smart application ********************)
529 let saturate_to_ref status metasenv subst ctx nref ty =
530 let height = height_of_ref status nref in
531 let rec aux metasenv ty args =
532 let ty,metasenv,moreargs =
533 NCicMetaSubst.saturate status ~delta:height metasenv subst ctx ty 0 in
535 | NCic.Const(NReference.Ref (_,NReference.Def _) as nre)
537 let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in
538 aux metasenv bo (args@moreargs)
539 | NCic.Appl(NCic.Const(NReference.Ref (_,NReference.Def _) as nre)::tl)
541 let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in
542 aux metasenv (NCic.Appl(bo::tl)) (args@moreargs)
543 | _ -> ty,metasenv,(args@moreargs)
547 let smart_apply t unit_eq status g =
548 let n,h,metasenv,subst,o = status#obj in
549 let gname, ctx, gty = List.assoc g metasenv in
550 (* let ggty = mk_cic_term context gty in *)
551 let status, t = disambiguate status ctx t None in
552 let status,t = term_of_cic_term status t ctx in
553 let _,_,metasenv,subst,_ = status#obj in
554 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
555 let ty,metasenv,args =
558 | NCic.Appl(NCic.Const(nref)::_) ->
559 saturate_to_ref status metasenv subst ctx nref ty
561 NCicMetaSubst.saturate status metasenv subst ctx ty 0 in
562 let metasenv,j,inst,_ = NCicMetaSubst.mk_meta metasenv ctx `IsTerm in
563 let status = status#set_obj (n,h,metasenv,subst,o) in
564 let pterm = if args=[] then t else
566 | NCic.Appl l -> NCic.Appl(l@args)
567 | _ -> NCic.Appl(t::args)
569 noprint(lazy("pterm " ^ (status#ppterm ctx [] [] pterm)));
570 noprint(lazy("pty " ^ (status#ppterm ctx [] [] ty)));
573 NUri.uri_of_string "cic:/matita/basics/logic/eq_coerc.con" in
574 let ref = NReference.reference_of_spec uri (NReference.Def(2)) in
578 NCic.Appl[eq_coerc;ty;NCic.Implicit `Type;pterm;inst] in
579 let smart = mk_cic_term ctx smart in
581 let status = instantiate status g smart in
582 let _,_,metasenv,subst,_ = status#obj in
583 let _,ctx,jty = List.assoc j metasenv in
584 let jty = NCicUntrusted.apply_subst status subst ctx jty in
585 noprint(lazy("goal " ^ (status#ppterm ctx [] [] jty)));
586 fast_eq_check unit_eq status j
588 | NCicEnvironment.ObjectNotFound s as e ->
589 raise (Error (lazy "eq_coerc non yet defined",Some e))
590 | Error _ as e -> debug_print (lazy "error"); raise e
592 let compare_statuses ~past ~present =
593 let _,_,past,_,_ = past#obj in
594 let _,_,present,_,_ = present#obj in
595 List.map fst (List.filter (fun (i,_) -> not(List.mem_assoc i past)) present),
596 List.map fst (List.filter (fun (i,_) -> not (List.mem_assoc i present)) past)
599 (* paramodulation has only an implicit knowledge of the symmetry of equality;
600 hence it is in trouble in proving (a = b) = (b = a) *)
601 let try_sym tac status g =
602 (* put the right uri *)
603 let sym_eq = Ast.Appl [Ast.Ident("sym_eq",`Ambiguous); Ast.Implicit `Vector] in
604 let _,_,metasenv,subst,_ = status#obj in
605 let _, context, gty = List.assoc g metasenv in
607 NCicParamod.is_equation status metasenv subst context gty
612 let new_status = instantiate_with_ast status g ("",0,sym_eq) in
613 let go, _ = compare_statuses ~past:status ~present:new_status in
614 assert (List.length go = 1);
615 let ng = List.hd go in
620 let smart_apply_tac t s =
621 let unit_eq = index_local_equations s#eq_cache s in
622 NTactics.distribute_tac (try_sym (smart_apply t unit_eq)) s
623 (* NTactics.distribute_tac (smart_apply t unit_eq) s *)
625 let smart_apply_auto t eq_cache =
626 NTactics.distribute_tac (try_sym (smart_apply t eq_cache))
627 (* NTactics.distribute_tac (smart_apply t eq_cache) *)
630 (****************** types **************)
633 type th_cache = (NCic.context * InvRelDiscriminationTree.t) list
635 (* cartesian: term set list -> term list set *)
638 [] -> NDiscriminationTree.TermListSet.empty
640 NDiscriminationTree.TermSet.fold
641 (fun x acc -> NDiscriminationTree.TermListSet.add [x] acc) l NDiscriminationTree.TermListSet.empty
643 let rest = cartesian tl in
644 NDiscriminationTree.TermSet.fold
646 NDiscriminationTree.TermListSet.fold (fun l acc' -> NDiscriminationTree.TermListSet.add (x::l) acc') rest acc
647 ) he NDiscriminationTree.TermListSet.empty
650 (* all_keys_of_cic_type: term -> term set *)
651 let all_keys_of_cic_type status metasenv subst context ty =
653 (* Here we are dropping the metasenv, but this should not raise any
654 exception (hopefully...) *)
656 NCicMetaSubst.saturate status ~delta:max_int metasenv subst context ty 0
662 NCic.Appl (he::tl) ->
665 let wty = NCicReduction.whd status ~delta:0 ~subst context ty in
667 NDiscriminationTree.TermSet.add ty (aux ty)
669 NDiscriminationTree.TermSet.union
670 (NDiscriminationTree.TermSet.add ty (aux ty))
671 (NDiscriminationTree.TermSet.add wty (aux wty))
674 NDiscriminationTree.TermListSet.fold
675 (fun l acc -> NDiscriminationTree.TermSet.add (NCic.Appl l) acc)
676 (cartesian ((NDiscriminationTree.TermSet.singleton he)::tl'))
677 NDiscriminationTree.TermSet.empty
678 | _ -> NDiscriminationTree.TermSet.empty
680 let ty,ity = saturate ty in
681 let wty,iwty = saturate (NCicReduction.whd status ~delta:0 ~subst context ty) in
683 [ity, NDiscriminationTree.TermSet.add ty (aux ty)]
685 [ity, NDiscriminationTree.TermSet.add ty (aux ty) ;
686 iwty, NDiscriminationTree.TermSet.add wty (aux wty) ]
689 let all_keys_of_type status t =
690 let _,_,metasenv,subst,_ = status#obj in
691 let context = ctx_of t in
692 let status, t = apply_subst status context t in
694 all_keys_of_cic_type status metasenv subst context
695 (snd (term_of_cic_term status t context))
699 (fun (intros,keys) ->
701 NDiscriminationTree.TermSet.fold
702 (fun t acc -> Ncic_termSet.add (mk_cic_term context t) acc)
703 keys Ncic_termSet.empty
708 let keys_of_type status orig_ty =
709 (* Here we are dropping the metasenv (in the status), but this should not
710 raise any exception (hopefully...) *)
711 let _, ty, _ = saturate ~delta:max_int status orig_ty in
712 let _, ty = apply_subst status (ctx_of ty) ty in
715 let orig_ty' = NCicTacReduction.normalize ~subst context orig_ty in
716 if orig_ty' <> orig_ty then
717 let ty',_,_= NCicMetaSubst.saturate ~delta:0 metasenv subst context orig_ty' 0 in
723 (*CSC: strange: we keep ty, ty normalized and ty ~delta:(h-1) *)
725 let _, ty = term_of_cic_term status ty (ctx_of ty) in
727 | NCic.Const (NReference.Ref (_,(NReference.Def h | NReference.Fix (_,_,h))))
728 | NCic.Appl (NCic.Const(NReference.Ref(_,(NReference.Def h | NReference.Fix (_,_,h))))::_)
730 let _,ty,_= saturate status ~delta:(h-1) orig_ty in
737 let all_keys_of_term status t =
738 let status, orig_ty = typeof status (ctx_of t) t in
739 all_keys_of_type status orig_ty
742 let keys_of_term status t =
743 let status, orig_ty = typeof status (ctx_of t) t in
744 keys_of_type status orig_ty
747 let mk_th_cache status gl =
749 (fun (status, acc) g ->
750 let gty = get_goalty status g in
751 let ctx = ctx_of gty in
752 noprint(lazy("th cache for: "^ppterm status gty));
753 noprint(lazy("th cache in: "^ppcontext status ctx));
754 if List.mem_assq ctx acc then status, acc else
755 let idx = InvRelDiscriminationTree.empty in
758 (fun (status, i, idx) _ ->
759 let t = mk_cic_term ctx (NCic.Rel i) in
760 let status, keys = keys_of_term status t in
761 noprint(lazy("indexing: "^ppterm status t ^ ": " ^ string_of_int (List.length keys)));
763 List.fold_left (fun idx k ->
764 InvRelDiscriminationTree.index idx k t) idx keys
769 status, (ctx, idx) :: acc)
773 let all_elements ctx cache =
774 let dummy = mk_cic_term ctx (NCic.Meta (0,(0, (NCic.Irl 0)))) in
776 let idx = List.assq ctx cache in
777 Ncic_termSet.elements
778 (InvRelDiscriminationTree.retrieve_unifiables idx dummy)
781 let add_to_th t c ty =
782 let key_c = ctx_of t in
783 if not (List.mem_assq key_c c) then
784 (key_c ,InvRelDiscriminationTree.index
785 InvRelDiscriminationTree.empty ty t ) :: c
787 let rec replace = function
789 | (x, idx) :: tl when x == key_c ->
790 (x, InvRelDiscriminationTree.index idx ty t) :: tl
791 | x :: tl -> x :: replace tl
796 let rm_from_th t c ty =
797 let key_c = ctx_of t in
798 if not (List.mem_assq key_c c) then assert false
800 let rec replace = function
802 | (x, idx) :: tl when x == key_c ->
803 (x, InvRelDiscriminationTree.remove_index idx ty t) :: tl
804 | x :: tl -> x :: replace tl
809 let pp_idx status idx =
810 InvRelDiscriminationTree.iter idx
812 noprint(lazy("K: " ^ NCicInverseRelIndexable.string_of_path k));
814 (fun t -> debug_print(lazy("\t"^ppterm status t)))
818 let pp_th (status: #NTacStatus.pstatus) =
821 noprint(lazy( "-----------------------------------------------"));
822 noprint(lazy( (status#ppcontext ~metasenv:[] ~subst:[] ctx)));
823 noprint(lazy( "||====> "));
827 let search_in_th gty th =
828 let c = ctx_of gty in
829 let rec aux acc = function
830 | [] -> (* Ncic_termSet.elements *) acc
833 let idx = List.assoc(*q*) k th in
834 let acc = Ncic_termSet.union acc
835 (InvRelDiscriminationTree.retrieve_unifiables idx gty)
838 with Not_found -> aux acc tl
840 aux Ncic_termSet.empty c
844 do_types : bool; (* solve goals in Type *)
845 last : bool; (* last goal: take first solution only *)
846 candidates: Ast.term list option;
854 {facts : th_cache; (* positive results *)
855 under_inspection : cic_term list * th_cache; (* to prune looping *)
856 failures : th_cache; (* to avoid repetitions *)
857 unit_eq : NCicParamod.state;
861 let add_to_trace status ~depth cache t =
864 print ~depth (lazy ("Adding to trace: " ^ NotationPp.pp_term status t));
865 {cache with trace = t::cache.trace}
866 | Ast.NCic _ (* local candidate *)
867 | _ -> (*not an application *) cache
869 let pptrace status tr =
870 (lazy ("Proof Trace: " ^ (String.concat ";"
871 (List.map (NotationPp.pp_term status) tr))))
873 let remove_from_trace cache t =
876 (match cache.trace with
877 | _::tl -> {cache with trace = tl}
879 | Ast.NCic _ (* local candidate *)
880 | _ -> (*not an application *) cache *)
883 type goal = int * sort (* goal, depth, sort *)
884 type fail = goal * cic_term
885 type candidate = int * Ast.term (* unique candidate number, candidate *)
887 exception Gaveup of th_cache (* failure cache *)
888 exception Proved of NTacStatus.tac_status * Ast.term list
890 (* let close_failures _ c = c;; *)
891 (* let prunable _ _ _ = false;; *)
892 (* let cache_examine cache gty = `Notfound;; *)
893 (* let put_in_subst s _ _ _ = s;; *)
894 (* let add_to_cache_and_del_from_orlist_if_green_cut _ _ c _ _ o f _ = c, o, f, false ;; *)
895 (* let cache_add_underinspection c _ _ = c;; *)
897 let init_cache ?(facts=[]) ?(under_inspection=[],[])
899 ?(unit_eq=NCicParamod.empty_state)
904 under_inspection = under_inspection;
908 let only signature _context candidate = true
910 (* TASSI: nel trie ci mettiamo solo il body, non il ty *)
912 NCicTypeChecker.typeof ~subst:[] ~metasenv:[] [] candidate
914 let height = fast_height_of_term status candidate_ty in
915 let rc = signature >= height in
917 noprint (lazy ("Filtro: " ^ status#ppterm ~context:[] ~subst:[]
918 ~metasenv:[] candidate ^ ": " ^ string_of_int height))
920 noprint (lazy ("Tengo: " ^ status#ppterm ~context:[] ~subst:[]
921 ~metasenv:[] candidate ^ ": " ^ string_of_int height));
926 let candidate_no = ref 0;;
928 let openg_no status = List.length (head_goals status#stack)
930 let sort_candidates status ctx candidates =
931 let _,_,metasenv,subst,_ = status#obj in
933 let status,ct = disambiguate status ctx ("",0,cand) None in
934 let status,t = term_of_cic_term status ct ctx in
935 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
936 let res = branch status (mk_cic_term ctx ty) in
937 noprint (lazy ("branch factor for: " ^ (ppterm status ct) ^ " = "
938 ^ (string_of_int res)));
941 let candidates = List.map (fun t -> branch t,t) candidates in
943 List.sort (fun (a,_) (b,_) -> a - b) candidates in
944 let candidates = List.map snd candidates in
945 noprint (lazy ("candidates =\n" ^ (String.concat "\n"
946 (List.map (NotationPp.pp_term status) candidates))));
949 let sort_new_elems l =
950 List.sort (fun (_,s1) (_,s2) -> openg_no s1 - openg_no s2) l
952 let rec stack_goals level gs =
957 let is_open = function
958 | (_,Continuationals.Stack.Open i) -> Some i
959 | (_,Continuationals.Stack.Closed _) -> None
961 HExtlib.filter_map is_open g @ stack_goals (level-1) s
964 let open_goals level status = stack_goals level status#stack
967 let try_candidate ?(smart=0) flags depth status eq_cache ctx t =
969 let old_og_no = List.length (open_goals (depth+1) status) in
970 debug_print ~depth (lazy ("try " ^ (NotationPp.pp_term status) t));
972 if smart= 0 then NTactics.apply_tac ("",0,t) status
973 else if smart = 1 then smart_apply_auto ("",0,t) eq_cache status
974 else (* smart = 2: both *)
975 try NTactics.apply_tac ("",0,t) status
977 smart_apply_auto ("",0,t) eq_cache status
979 (* we compare the expected branching with the actual one and
980 prune the candidate when the latter is larger. The optimization
981 is meant to rule out stange applications of flexible terms,
982 such as the application of eq_f that always succeeds.
983 There is some gain but less than expected *)
984 let og_no = List.length (open_goals (depth+1) status) in
985 let status, cict = disambiguate status ctx ("",0,t) None in
986 let status,ct = term_of_cic_term status cict ctx in
987 let _,_,metasenv,subst,_ = status#obj in
988 let ty = NCicTypeChecker.typeof status subst metasenv ctx ct in
989 let res = branch status (mk_cic_term ctx ty) in
990 let diff = og_no - old_og_no in
991 debug_print (lazy ("expected branching: " ^ (string_of_int res)));
992 debug_print (lazy ("actual: branching" ^ (string_of_int diff)));
993 (* some flexibility *)
994 if diff > res && res > 0 (* facts are never pruned *) then
995 (debug_print (lazy ("branch factor for: " ^ (ppterm status cict) ^ " = "
996 ^ (string_of_int res) ^ " vs. " ^ (string_of_int diff)));
997 debug_print ~depth (lazy "strange application"); None)
999 (incr candidate_no; Some ((!candidate_no,t),status))
1000 with Error (msg,exn) -> debug_print ~depth (lazy "failed"); None
1003 let sort_of status subst metasenv ctx t =
1004 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
1005 let metasenv',ty = NCicUnification.fix_sorts status metasenv subst ty in
1006 assert (metasenv = metasenv');
1007 NCicTypeChecker.typeof status subst metasenv ctx ty
1010 let type0= NUri.uri_of_string ("cic:/matita/pts/Type0.univ")
1013 let perforate_small status subst metasenv context t =
1014 let rec aux = function
1015 | NCic.Appl (hd::tl) ->
1017 let s = sort_of status subst metasenv context t in
1019 | NCic.Sort(NCic.Type [`Type,u])
1020 when u=type0 -> NCic.Meta (0,(0,NCic.Irl 0))
1023 NCic.Appl (hd::List.map map tl)
1029 let get_cands retrieve_for diff empty gty weak_gty =
1030 let cands = retrieve_for gty in
1032 | None -> cands, empty
1034 let more_cands = retrieve_for weak_gty in
1035 cands, diff more_cands cands
1038 let get_candidates ?(smart=true) depth flags status cache signature gty =
1039 let universe = status#auto_cache in
1040 let _,_,metasenv,subst,_ = status#obj in
1041 let context = ctx_of gty in
1042 let _, raw_gty = term_of_cic_term status gty context in
1043 let is_prod, is_eq =
1044 let status, t = term_of_cic_term status gty context in
1045 let t = NCicReduction.whd status subst context t in
1047 | NCic.Prod _ -> true, false
1048 | _ -> false, NCicParamod.is_equation status metasenv subst context t
1050 debug_print ~depth (lazy ("gty:" ^ NTacStatus.ppterm status gty));
1052 NCicParamod.is_equation status metasenv subst context raw_gty
1054 let raw_weak_gty, weak_gty =
1061 perforate_small status subst metasenv context raw_gty in
1062 let weak = mk_cic_term context raw_weak in
1063 debug_print ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1064 Some raw_weak, Some (weak)
1068 (* we now compute global candidates *)
1069 let global_cands, smart_global_cands =
1071 let to_ast = function
1072 | NCic.Const r when true
1073 (*is_relevant statistics r*) -> Some (Ast.NRef r)
1074 (* | NCic.Const _ -> None *)
1075 | _ -> assert false in
1077 to_ast (NDiscriminationTree.TermSet.elements s) in
1080 (NDiscriminationTree.DiscriminationTree.retrieve_unifiables universe)
1081 NDiscriminationTree.TermSet.diff
1082 NDiscriminationTree.TermSet.empty
1083 raw_gty raw_weak_gty in
1085 (* we now compute local candidates *)
1086 let local_cands,smart_local_cands =
1089 let _status, t = term_of_cic_term status t context
1091 List.map to_ast (Ncic_termSet.elements s) in
1094 (fun ty -> search_in_th ty cache)
1095 Ncic_termSet.diff Ncic_termSet.empty gty weak_gty in
1097 (* we now splits candidates in facts or not facts *)
1098 let test = is_a_fact_ast status subst metasenv context in
1099 let by,given_candidates =
1100 match flags.candidates with
1102 | None -> false, [] in
1103 (* we compute candidates to be applied in normal mode, splitted in
1104 facts and not facts *)
1105 let candidates_facts,candidates_other =
1106 let gl1,gl2 = List.partition test global_cands in
1107 let ll1,ll2 = List.partition test local_cands in
1108 (* if the goal is an equation we avoid to apply unit equalities,
1109 since superposition should take care of them; refl is an
1110 exception since it prompts for convertibility *)
1111 let l1 = if is_eq then [Ast.Ident("refl",`Ambiguous)] else gl1@ll1 in
1113 (* if smart given candidates are applied in smart mode *)
1114 if by && smart then ll2
1115 else if by then given_candidates@ll2
1119 (* we now compute candidates to be applied in smart mode, splitted in
1120 facts and not facts *)
1121 let smart_candidates_facts, smart_candidates_other =
1122 if is_prod || not(smart) then [],[]
1124 let sgl1,sgl2 = List.partition test smart_global_cands in
1125 let sll1,sll2 = List.partition test smart_local_cands in
1126 let l1 = if is_eq then [] else sgl1@sll1 in
1128 if by && smart then given_candidates@sll2
1129 else if by then sll2
1134 smart_candidates_facts,
1135 sort_candidates status context (candidates_other),
1136 sort_candidates status context (smart_candidates_other)
1139 let applicative_case depth signature status flags gty cache =
1140 app_counter:= !app_counter+1;
1141 let _,_,metasenv,subst,_ = status#obj in
1142 let context = ctx_of gty in
1143 let tcache = cache.facts in
1144 let is_prod, is_eq =
1145 let status, t = term_of_cic_term status gty context in
1146 let t = NCicReduction.whd status subst context t in
1148 | NCic.Prod _ -> true, false
1149 | _ -> false, NCicParamod.is_equation status metasenv subst context t
1151 debug_print ~depth (lazy (string_of_bool is_eq));
1153 let candidates_facts, smart_candidates_facts,
1154 candidates_other, smart_candidates_other =
1155 get_candidates ~smart:true depth
1156 flags status tcache signature gty
1158 let sm = if is_eq || is_prod then 0 else 2 in
1159 let sm1 = if flags.last then 2 else 0 in
1160 let maxd = (depth + 1 = flags.maxdepth) in
1161 let try_candidates only_one sm acc candidates =
1164 if (only_one && (elems <> [])) then elems
1166 match try_candidate (~smart:sm)
1167 flags depth status cache.unit_eq context cand with
1169 | Some x -> x::elems)
1172 (* if the goal is the last one we stop at the first fact *)
1173 let elems = try_candidates flags.last sm [] candidates_facts in
1174 (* now we add smart_facts *)
1175 let elems = try_candidates flags.last sm elems smart_candidates_facts in
1176 (* if we are at maxdepth and the goal is not a product we are done
1177 similarly, if the goal is the last one and we already found a
1179 if (maxd && not(is_prod)) || (flags.last && elems<>[]) then elems
1181 let elems = try_candidates false 2 elems candidates_other in
1182 debug_print ~depth (lazy ("not facts: try smart application"));
1183 try_candidates false 2 elems smart_candidates_other
1189 (* gty is supposed to be meta-closed *)
1190 let is_subsumed depth filter_depth status gty cache =
1191 if cache=[] then false else (
1192 debug_print ~depth (lazy("Subsuming " ^ (ppterm status gty)));
1193 let n,h,metasenv,subst,obj = status#obj in
1194 let ctx = ctx_of gty in
1195 let _ , raw_gty = term_of_cic_term status gty ctx in
1196 let target = NCicSubstitution.lift status 1 raw_gty in
1197 (* we compute candidates using the perforated type *)
1204 perforate_small status subst metasenv ctx raw_gty in
1205 let weak = mk_cic_term ctx raw_weak in
1206 debug_print ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1210 (* candidates must only be searched w.r.t the given context *)
1213 let idx = List.assq ctx cache in
1216 Ncic_termSet.elements
1217 (InvRelDiscriminationTree.retrieve_unifiables idx weak)
1219 with Not_found -> []
1221 (* this is a dirty trick: the first argument of an application is used
1222 to remember at which depth a goal failed *)
1224 let ctx = ctx_of t in
1225 let _, src = term_of_cic_term status t ctx in
1227 | NCic.Appl [NCic.Implicit (`Typeof d); t]
1228 when d <= depth -> Some (mk_cic_term ctx t)
1231 if filter_depth then HExtlib.filter_map filter candidates else candidates in
1233 (lazy ("failure candidates: " ^ string_of_int (List.length candidates)));
1237 let _ , source = term_of_cic_term status t ctx in
1239 NCic.Prod("foo",source,target) in
1240 let metasenv,j,_,_ =
1241 NCicMetaSubst.mk_meta
1242 metasenv ctx ~with_type:implication `IsType in
1243 let status = status#set_obj (n,h,metasenv,subst,obj) in
1244 let status = status#set_stack [([1,Open j],[],[],`NoTag)] in
1246 let status = NTactics.intro_tac "foo" status in
1248 NTactics.apply_tac ("",0,Ast.NCic (NCic.Rel 1)) status
1250 if (head_goals status#stack = []) then raise Found
1255 with Found -> debug_print ~depth (lazy "success");true)
1258 let rec guess_name name ctx =
1259 if name = "_" then guess_name "auto" ctx else
1260 if not (List.mem_assoc name ctx) then name else
1261 guess_name (name^"'") ctx
1264 let is_prod status =
1265 let _, ctx, gty = current_goal status in
1266 let status, gty = apply_subst status ctx gty in
1267 let _, raw_gty = term_of_cic_term status gty ctx in
1269 | NCic.Prod (name,src,_) ->
1270 let status, src = whd status ~delta:0 ctx (mk_cic_term ctx src) in
1271 (match snd (term_of_cic_term status src ctx) with
1272 | NCic.Const(NReference.Ref (_,NReference.Ind _) as r)
1273 | NCic.Appl (NCic.Const(NReference.Ref (_,NReference.Ind _) as r)::_) ->
1274 let _,_,itys,_,_ = NCicEnvironment.get_checked_indtys status r in
1276 (* | [_,_,_,[_;_]] con nat va, ovviamente, in loop *)
1278 | [_,_,_,[]] -> `Inductive (guess_name name ctx)
1279 | _ -> `Some (guess_name name ctx))
1280 | _ -> `Some (guess_name name ctx))
1283 let intro ~depth status facts name =
1284 let status = NTactics.intro_tac name status in
1285 let _, ctx, ngty = current_goal status in
1286 let t = mk_cic_term ctx (NCic.Rel 1) in
1287 let status, keys = keys_of_term status t in
1288 let facts = List.fold_left (add_to_th t) facts keys in
1289 debug_print ~depth (lazy ("intro: "^ name));
1290 (* unprovability is not stable w.r.t introduction *)
1294 let rec intros_facts ~depth status facts =
1295 if List.length (head_goals status#stack) <> 1 then status, facts else
1296 match is_prod status with
1300 intro ~depth status facts name
1301 in intros_facts ~depth status facts
1302 (* | `Inductive name ->
1303 let status = NTactics.case1_tac name status in
1304 intros_facts ~depth status facts *)
1305 | _ -> status, facts
1308 let intros ~depth status cache =
1309 match is_prod status with
1312 let trace = cache.trace in
1314 intros_facts ~depth status cache.facts
1316 if head_goals status#stack = [] then
1317 let status = NTactics.merge_tac status in
1318 [(0,Ast.Ident("__intros",`Ambiguous)),status], cache
1320 (* we reindex the equation from scratch *)
1321 let unit_eq = index_local_equations status#eq_cache status in
1322 let status = NTactics.merge_tac status in
1323 [(0,Ast.Ident("__intros",`Ambiguous)),status],
1324 init_cache ~facts ~unit_eq () ~trace
1328 let reduce ~whd ~depth status g =
1329 let n,h,metasenv,subst,o = status#obj in
1330 let attr, ctx, ty = NCicUtils.lookup_meta g metasenv in
1331 let ty = NCicUntrusted.apply_subst status subst ctx ty in
1333 (if whd then NCicReduction.whd else NCicTacReduction.normalize) status ~subst ctx ty
1338 (lazy ("reduced to: "^ status#ppterm ctx subst metasenv ty'));
1340 (g,(attr,ctx,ty'))::(List.filter (fun (i,_) -> i<>g) metasenv)
1342 let status = status#set_obj (n,h,metasenv,subst,o) in
1343 (* we merge to gain a depth level; the previous goal level should
1345 let status = NTactics.merge_tac status in
1347 [(!candidate_no,Ast.Ident("__whd",`Ambiguous)),status])
1350 let do_something signature flags status g depth gty cache =
1351 let l0, cache = intros ~depth status cache in
1352 if l0 <> [] then l0, cache
1355 let l = reduce ~whd:true ~depth status g in
1356 (* if l <> [] then l,cache else *)
1357 (* backward aplications *)
1362 ((!candidate_no,Ast.Ident("__paramod",`Ambiguous)),s))
1363 (auto_eq_check cache.unit_eq status)
1366 if ((l1 <> []) && flags.last) then [] else
1367 applicative_case depth signature status flags gty cache
1371 (fun ((_,t),_) -> toref incr_nominations statistics t) l2;
1372 (* states in l1 have have an empty set of subgoals: no point to sort them *)
1374 (lazy ("alternatives = " ^ (string_of_int (List.length (l1@l@l2)))));
1375 (* we order alternatives w.r.t the number of subgoals they open *)
1376 l1 @ (sort_new_elems l2) @ l, cache
1379 let pp_goal = function
1380 | (_,Continuationals.Stack.Open i)
1381 | (_,Continuationals.Stack.Closed i) -> string_of_int i
1384 let pp_goals status l =
1388 let gty = get_goalty status i in
1389 NTacStatus.ppterm status gty)
1396 let compare = Pervasives.compare
1400 module MS = HTopoSort.Make(M)
1403 let sort_tac status =
1405 match status#stack with
1406 | [] -> assert false
1407 | (goals, t, k, tag) :: s ->
1408 let g = head_goals status#stack in
1410 (List.rev (MS.topological_sort g (deps status))) in
1411 noprint (lazy ("old g = " ^
1412 String.concat "," (List.map string_of_int g)));
1413 noprint (lazy ("sorted goals = " ^
1414 String.concat "," (List.map string_of_int sortedg)));
1415 let is_it i = function
1416 | (_,Continuationals.Stack.Open j )
1417 | (_,Continuationals.Stack.Closed j ) -> i = j
1420 List.map (fun i -> List.find (is_it i) goals) sortedg
1422 (sorted_goals, t, k, tag) :: s
1424 status#set_stack gstatus
1427 let clean_up_tac status =
1429 match status#stack with
1430 | [] -> assert false
1431 | (g, t, k, tag) :: s ->
1432 let is_open = function
1433 | (_,Continuationals.Stack.Open _) -> true
1434 | (_,Continuationals.Stack.Closed _) -> false
1436 let g' = List.filter is_open g in
1437 (g', t, k, tag) :: s
1439 status#set_stack gstatus
1442 let focus_tac focus status =
1444 match status#stack with
1445 | [] -> assert false
1446 | (g, t, k, tag) :: s ->
1447 let in_focus = function
1448 | (_,Continuationals.Stack.Open i)
1449 | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1451 let focus,others = List.partition in_focus g
1453 (* we need to mark it as a BranchTag, otherwise cannot merge later *)
1454 (focus,[],[],`BranchTag) :: (others, t, k, tag) :: s
1456 status#set_stack gstatus
1459 let deep_focus_tac level focus status =
1460 let in_focus = function
1461 | (_,Continuationals.Stack.Open i)
1462 | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1464 let rec slice level gs =
1465 if level = 0 then [],[],gs else
1467 | [] -> assert false
1468 | (g, t, k, tag) :: s ->
1469 let f,o,gs = slice (level-1) s in
1470 let f1,o1 = List.partition in_focus g
1472 (f1,[],[],`BranchTag)::f, (o1, t, k, tag)::o, gs
1475 let f,o,s = slice level status#stack in f@o@s
1477 status#set_stack gstatus
1480 let move_to_side level status =
1481 match status#stack with
1482 | [] -> assert false
1484 let is_open = function
1485 | (_,Continuationals.Stack.Open i) -> Some i
1486 | (_,Continuationals.Stack.Closed _) -> None
1488 let others = menv_closure status (stack_goals (level-1) tl) in
1489 List.for_all (fun i -> IntSet.mem i others)
1490 (HExtlib.filter_map is_open g)
1492 let top_cache ~depth top status cache =
1494 let unit_eq = index_local_equations status#eq_cache status in
1495 {cache with unit_eq = unit_eq}
1498 let rec auto_clusters ?(top=false)
1499 flags signature cache depth status : unit =
1500 debug_print ~depth (lazy ("entering auto clusters at depth " ^
1501 (string_of_int depth)));
1502 debug_print ~depth (pptrace status cache.trace);
1503 (* ignore(Unix.select [] [] [] 0.01); *)
1504 let status = clean_up_tac status in
1505 let goals = head_goals status#stack in
1507 if depth = 0 then raise (Proved (status, cache.trace))
1509 let status = NTactics.merge_tac status in
1511 let l,tree = cache.under_inspection in
1513 | [] -> cache (* possible because of intros that cleans the cache *)
1514 | a::tl -> let tree = rm_from_th a tree a in
1515 {cache with under_inspection = tl,tree}
1517 auto_clusters flags signature cache (depth-1) status
1518 else if List.length goals < 2 then
1519 let cache = top_cache ~depth top status cache in
1520 auto_main flags signature cache depth status
1522 let all_goals = open_goals (depth+1) status in
1523 debug_print ~depth (lazy ("goals = " ^
1524 String.concat "," (List.map string_of_int all_goals)));
1525 let classes = HExtlib.clusters (deps status) all_goals in
1526 (* if any of the classes exceed maxwidth we fail *)
1529 if List.length gl > flags.maxwidth then
1531 debug_print ~depth (lazy "FAIL GLOBAL WIDTH");
1532 HLog.warn (sprintf "global width (%u) exceeded: %u"
1533 flags.maxwidth (List.length gl));
1534 raise (Gaveup cache.failures)
1535 end else ()) classes;
1536 if List.length classes = 1 then
1538 {flags with last = (List.length all_goals = 1)} in
1539 (* no need to cluster *)
1540 let cache = top_cache ~depth top status cache in
1541 auto_main flags signature cache depth status
1543 let classes = if top then List.rev classes else classes in
1549 ("cluster:" ^ String.concat "," (List.map string_of_int l)))
1551 (* we now process each cluster *)
1552 let status,cache,b =
1554 (fun (status,cache,b) gl ->
1556 {flags with last = (List.length gl = 1)} in
1557 let lold = List.length status#stack in
1558 debug_print ~depth (lazy ("stack length = " ^
1559 (string_of_int lold)));
1560 let fstatus = deep_focus_tac (depth+1) gl status in
1561 let cache = top_cache ~depth top fstatus cache in
1563 debug_print ~depth (lazy ("focusing on" ^
1564 String.concat "," (List.map string_of_int gl)));
1565 auto_main flags signature cache depth fstatus; assert false
1567 | Proved(status,trace) ->
1568 let status = NTactics.merge_tac status in
1569 let cache = {cache with trace = trace} in
1570 let lnew = List.length status#stack in
1571 assert (lold = lnew);
1573 | Gaveup failures when top ->
1574 let cache = {cache with failures = failures} in
1577 (status,cache,false) classes
1579 let rec final_merge n s =
1580 if n = 0 then s else final_merge (n-1) (NTactics.merge_tac s)
1581 in let status = final_merge depth status
1582 in if b then raise (Proved(status,cache.trace)) else raise (Gaveup cache.failures)
1586 (* BRAND NEW VERSION *)
1587 auto_main flags signature cache depth status: unit =
1588 debug_print ~depth (lazy "entering auto main");
1589 debug_print ~depth (pptrace status cache.trace);
1590 debug_print ~depth (lazy ("stack length = " ^
1591 (string_of_int (List.length status#stack))));
1592 (* ignore(Unix.select [] [] [] 0.01); *)
1593 let status = sort_tac (clean_up_tac status) in
1594 let goals = head_goals status#stack in
1596 | [] when depth = 0 -> raise (Proved (status,cache.trace))
1598 let status = NTactics.merge_tac status in
1600 let l,tree = cache.under_inspection in
1602 | [] -> cache (* possible because of intros that cleans the cache *)
1603 | a::tl -> let tree = rm_from_th a tree a in
1604 {cache with under_inspection = tl,tree}
1606 auto_clusters flags signature cache (depth-1) status
1608 if depth > 0 && move_to_side depth status
1610 let status = NTactics.merge_tac status in
1612 let l,tree = cache.under_inspection in
1614 | [] -> cache (* possible because of intros that cleans the cache*)
1615 | a::tl -> let tree = rm_from_th a tree a in
1616 {cache with under_inspection = tl,tree}
1618 auto_clusters flags signature cache (depth-1) status
1620 let ng = List.length goals in
1621 (* moved inside auto_clusters *)
1622 if ng > flags.maxwidth then begin
1623 debug_print ~depth (lazy "FAIL LOCAL WIDTH");
1624 HLog.warn (sprintf "local width (%u) exceeded: %u"
1626 raise (Gaveup cache.failures)
1627 end else if depth = flags.maxdepth then
1628 raise (Gaveup cache.failures)
1630 let status = NTactics.branch_tac ~force:true status in
1631 let g,gctx, gty = current_goal status in
1632 let ctx,ty = close status g in
1633 let closegty = mk_cic_term ctx ty in
1634 let status, gty = apply_subst status gctx gty in
1635 debug_print ~depth (lazy("Attacking goal " ^
1636 string_of_int g ^ " : "^ppterm status gty));
1637 debug_print ~depth (lazy ("current failures: " ^
1638 string_of_int (List.length (all_elements ctx cache.failures))));
1640 let _,_,metasenv,subst,_ = status#obj in
1641 NCicParamod.is_equation status metasenv subst ctx ty in
1642 (* if the goal is an equality we artificially raise its depth up to
1643 flags.maxdepth - 1 *)
1644 if (not flags.last && is_eq && (depth < (flags.maxdepth -1))) then
1645 (* for efficiency reasons, in this case we severely cripple the
1647 (debug_print ~depth (lazy ("RAISING DEPTH TO " ^ string_of_int (depth+1)));
1648 auto_main flags signature cache (depth+1) status)
1649 (* check for loops *)
1650 else if is_subsumed depth false status closegty (snd cache.under_inspection) then
1651 (debug_print ~depth (lazy "SUBSUMED");
1652 raise (Gaveup cache.failures))
1653 (* check for failures *)
1654 else if is_subsumed depth true status closegty cache.failures then
1655 (debug_print ~depth (lazy "ALREADY MET");
1656 raise (Gaveup cache.failures))
1658 let new_sig = height_of_goal g status in
1659 if new_sig < signature then
1660 (debug_print ~depth (lazy ("news = " ^ (string_of_int new_sig)));
1661 debug_print ~depth (lazy ("olds = " ^ (string_of_int signature))));
1662 let alternatives, cache =
1663 do_something signature flags status g depth gty cache in
1666 let l,tree = cache.under_inspection in
1667 let l,tree = closegty::l, add_to_th closegty tree closegty in
1668 {cache with under_inspection = l,tree}
1672 (fun allfailures ((_,t),status) ->
1674 (lazy ("(re)considering goal " ^
1675 (string_of_int g) ^" : "^ppterm status gty));
1676 debug_print (~depth:depth)
1677 (lazy ("Case: " ^ NotationPp.pp_term status t));
1679 if t=Ast.Ident("__whd",`Ambiguous) ||
1680 t=Ast.Ident("__intros",`Ambiguous)
1682 else depth+1,loop_cache in
1683 let cache = add_to_trace status ~depth cache t in
1684 let cache = {cache with failures = allfailures} in
1686 auto_clusters flags signature cache depth status;
1689 debug_print ~depth (lazy "Failed");
1691 cache.failures alternatives in
1695 let dty = NCic.Appl [NCic.Implicit (`Typeof depth); ty] in
1698 prerr_endline ("FAILURE : " ^ ppterm status gty);
1699 add_to_th newfail failures closegty
1701 debug_print ~depth (lazy "no more candidates");
1702 raise (Gaveup failures)
1705 let int name l def =
1706 try int_of_string (List.assoc name l)
1707 with Failure _ | Not_found -> def
1710 module AstSet = Set.Make(struct type t = Ast.term let compare = compare end)
1712 let cleanup_trace s trace =
1713 (* removing duplicates *)
1716 (fun acc t -> AstSet.add t acc)
1717 AstSet.empty trace in
1718 let trace = AstSet.elements trace_set
1719 (* filtering facts *)
1723 | Ast.NRef (NReference.Ref (u,_)) -> not (is_a_fact_obj s u)
1727 let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =
1728 let oldstatus = status in
1729 let status = (status:> NTacStatus.tac_status) in
1730 let goals = head_goals status#stack in
1731 let status, facts = mk_th_cache status goals in
1732 (* let unit_eq = index_local_equations status#eq_cache status in *)
1733 let cache = init_cache ~facts () in
1734 (* pp_th status facts; *)
1736 NDiscriminationTree.DiscriminationTree.iter status#auto_cache (fun p t ->
1737 (*debug_*)print (lazy(
1738 NDiscriminationTree.NCicIndexable.string_of_path p ^ " |--> " ^
1739 String.concat "\n " (List.map (
1740 status#ppterm ~metasenv:[] ~context:[] ~subst:[])
1741 (NDiscriminationTree.TermSet.elements t))
1744 (* To allow using Rels in the user-specified candidates, we need a context
1745 * but in the case where multiple goals are open, there is no single context
1746 * to type the Rels. At this time, we require that Rels be typed in the
1747 * context of the first selected goal *)
1748 let _,ctx,_ = current_goal ~single_goal:false status in
1749 let status, candidates =
1751 | None -> status, None
1753 let to_Ast (st,l) t =
1754 let st, res = disambiguate st ctx t None in
1755 let st, res = term_of_cic_term st res (ctx_of res)
1756 in (st, Ast.NCic res::l)
1758 let status, l' = List.fold_left to_Ast (status,[]) l in
1761 let depth = int "depth" flags 3 in
1762 let size = int "size" flags 10 in
1763 let width = int "width" flags 4 (* (3+List.length goals)*) in
1765 (* let goals = List.map (fun i -> (i,P)) goals in *)
1766 let signature = height_of_goals status in
1769 candidates = candidates;
1773 timeout = Unix.gettimeofday() +. 3000.;
1776 let initial_time = Unix.gettimeofday() in
1781 ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1783 ("Applicative nodes:"^string_of_int !app_counter));
1784 raise (Error (lazy "auto gave up", None)))
1786 let _ = debug_print (lazy("\n\nRound "^string_of_int x^"\n")) in
1787 let flags = { flags with maxdepth = x }
1789 try auto_clusters (~top:true) flags signature cache 0 status;assert false
1791 try auto_main flags signature cache 0 status;assert false
1794 | Gaveup _ -> up_to (x+1) y
1795 | Proved (s,trace) ->
1796 debug_print (lazy ("proved at depth " ^ string_of_int x));
1797 List.iter (toref incr_uses statistics) trace;
1798 let _ = debug_print (pptrace status trace) in
1799 let trace = cleanup_trace s trace in
1800 let _ = debug_print (pptrace status trace) in
1803 | (g,t,k,f) :: rest -> (filter_open g,t,k,f):: rest
1806 let s = s#set_stack stack in
1808 oldstatus#set_status s
1810 let s = up_to depth depth in
1811 debug_print (print_stat status statistics);
1813 ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1815 ("Applicative nodes:"^string_of_int !app_counter));
1819 let auto_tac ~params:(_,flags as params) ?trace_ref =
1820 if List.mem_assoc "demod" flags then
1822 else if List.mem_assoc "paramod" flags then
1824 else if List.mem_assoc "fast_paramod" flags then
1825 fast_eq_check_tac ~params
1826 else auto_tac ~params ?trace_ref