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
29 let equal = NReference.eq
30 let compare = NReference.compare
31 let hash = NReference.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 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)
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
161 let height_of_ref status (NReference.Ref (uri, x)) =
166 | NReference.CoFix _ ->
167 let _,height,_,_,_ = NCicEnvironment.get_checked_obj status uri in
169 | NReference.Def h -> h
170 | NReference.Fix (_,_,h) -> h
173 (*************************** height functions ********************************)
174 let fast_height_of_term status t =
178 NCic.Meta (_,(_,NCic.Ctx l)) -> List.iter aux l
182 | NCic.Implicit _ -> assert false
185 prerr_endline (status#ppterm ~metasenv:[] ~subst:[]
186 ~context:[] t ^ ":" ^ string_of_int (height_of_ref status nref));
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
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
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);
214 let height_of_goals status =
215 let open_goals = head_goals status#stack in
216 assert (List.length open_goals > 0);
220 h := max !h (height_of_goal open_goal status))
222 noprint (lazy ("altezza sequente: " ^ string_of_int !h));
226 (* =============================== paramod =========================== *)
227 let solve f status eq_cache goal =
230 if fast then NCicParamod.fast_eq_check
231 else NCicParamod.paramod in
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) =
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 *)
249 (status#set_coerc_db NCicCoercion.empty_db)
250 metasenv subst ctx pt (`XTSome gty)
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))
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" ^
268 "\n in the environment\n" ^
269 status#ppmetasenv subst metasenv)); None
270 | Sys.Break as e -> raise e
273 HExtlib.filter_map build_status
274 (f status metasenv subst ctx eq_cache (NCic.Rel ~-1,gty))
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))
283 let dist_fast_eq_check eq_cache s =
284 NTactics.distribute_tac (fast_eq_check eq_cache) s
287 let auto_eq_check eq_cache status =
289 let s = dist_fast_eq_check eq_cache status in
292 | Error _ -> debug_print (lazy ("no paramod proof found"));[]
295 let index_local_equations eq_cache status =
296 noprint (lazy "indexing equations");
297 let open_goals = head_goals status#stack in
298 let open_goal = List.hd open_goals in
299 let ngty = get_goalty status open_goal in
300 let _,_,metasenv,subst,_ = status#obj in
301 let ctx = apply_subst_context ~fix_projections:true status (ctx_of ngty) in
306 let t = NCic.Rel !c in
308 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
309 if is_a_fact status (mk_cic_term ctx ty) then
310 (debug_print(lazy("eq indexing " ^ (status#ppterm ctx subst metasenv ty)));
311 NCicParamod.forward_infer_step status metasenv subst ctx eq_cache t ty)
313 (noprint (lazy ("not a fact: " ^ (status#ppterm ctx subst metasenv ty)));
316 | NCicTypeChecker.TypeCheckerFailure _
317 | NCicTypeChecker.AssertFailure _ -> eq_cache)
321 let index_local_equations2 eq_cache status open_goal lemmas nohyps =
322 noprint (lazy "indexing equations");
323 let eq_cache,lemmas =
326 | Some l -> NCicParamod.empty_state,l
328 let ngty = get_goalty status open_goal in
329 let _,_,metasenv,subst,_ = status#obj in
330 let ctx = apply_subst_context ~fix_projections:true status (ctx_of ngty) in
333 (fun (status,lemmas) l ->
334 let status,l = NTacStatus.disambiguate status ctx l `XTNone in
335 let status,l = NTacStatus.term_of_cic_term status l ctx in
337 (status,[]) lemmas in
338 let local_equations =
339 if nohyps then [] else
340 List.map (fun i -> NCic.Rel (i + 1))
341 (HExtlib.list_seq 1 (List.length ctx)) in
342 let lemmas = lemmas @ local_equations in
346 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
347 if is_a_fact status (mk_cic_term ctx ty) then
348 (debug_print(lazy("eq indexing " ^ (status#ppterm ctx subst metasenv ty)));
349 NCicParamod.forward_infer_step status metasenv subst ctx eq_cache t ty)
351 (noprint (lazy ("not a fact: " ^ (status#ppterm ctx subst metasenv ty)));
354 | NCicTypeChecker.TypeCheckerFailure _
355 | NCicTypeChecker.AssertFailure _ -> eq_cache)
359 let fast_eq_check_tac ~params s =
360 let unit_eq = index_local_equations s#eq_cache s in
361 dist_fast_eq_check unit_eq s
364 let paramod eq_cache status goal =
365 match solve NCicParamod.paramod status eq_cache goal with
366 | [] -> raise (Error (lazy "no proof found",None))
370 let paramod_tac ~params s =
371 let unit_eq = index_local_equations s#eq_cache s in
372 NTactics.distribute_tac (paramod unit_eq) s
375 let demod eq_cache status goal =
376 match solve NCicParamod.demod status eq_cache goal with
377 | [] -> raise (Error (lazy "no progress",None))
381 let demod_tac ~params s =
383 index_local_equations2 s#eq_cache s i (fst params)
384 (List.mem_assoc "nohyps" (snd params))
386 NTactics.distribute_tac (fun s i -> demod (unit_eq s i) s i) s
390 let fast_eq_check_tac_all ~params eq_cache status =
391 let g,_,_ = current_goal status in
392 let allstates = fast_eq_check_all status eq_cache g in
393 let pseudo_low_tac s _ _ = s in
394 let pseudo_low_tactics =
395 List.map pseudo_low_tac allstates
397 List.map (fun f -> NTactics.distribute_tac f status) pseudo_low_tactics
402 let demod status eq_cache goal =
403 let n,h,metasenv,subst,o = status#obj in
404 let gname, ctx, gty = List.assoc goal metasenv in
405 let gty = NCicUntrusted.apply_subst subst ctx gty in
407 let demod_tac ~params s =
408 let unit_eq = index_local_equations s#eq_cache s in
409 dist_fast_eq_check unit_eq s
412 (*************** subsumption ****************)
414 let close_wrt_context status =
418 | name, NCic.Decl t -> NCic.Prod(name,t,ty)
419 | name, NCic.Def(bo, _) -> NCicSubstitution.subst status bo ty)
422 let args_for_context ?(k=1) ctx =
425 (fun (n,l) ctx_entry ->
427 | name, NCic.Decl t -> n+1,NCic.Rel(n)::l
428 | name, NCic.Def(bo, _) -> n+1,l)
432 let constant_for_meta status ctx ty i =
433 let name = "cic:/foo"^(string_of_int i)^".con" in
434 let uri = NUri.uri_of_string name in
435 let ty = close_wrt_context status ty ctx in
436 (* prerr_endline (status#ppterm [] [] [] ty); *)
437 let attr = (`Generated,`Definition,`Local) in
438 let obj = NCic.Constant([],name,None,ty,attr) in
439 (* Constant of relevance * string * term option * term * c_attr *)
443 let refresh metasenv =
445 (fun (metasenv,subst) (i,(iattr,ctx,ty)) ->
446 let ikind = NCicUntrusted.kind_of_meta iattr in
447 let metasenv,j,instance,ty =
448 NCicMetaSubst.mk_meta ~attrs:iattr
449 metasenv ctx ~with_type:ty ikind in
450 let s_entry = i,(iattr, ctx, instance, ty) in
451 let metasenv = List.filter (fun x,_ -> i <> x) metasenv in
452 metasenv,s_entry::subst)
453 (metasenv,[]) metasenv
455 (* close metasenv returns a ground instance of all the metas in the
456 metasenv, insantiatied with axioms, and the list of these axioms *)
457 let close_metasenv status metasenv subst =
459 let metasenv = NCicUntrusted.apply_subst_metasenv subst metasenv in
461 let metasenv = NCicUntrusted.sort_metasenv status subst metasenv in
463 (fun (subst,objs) (i,(iattr,ctx,ty)) ->
464 let ty = NCicUntrusted.apply_subst status subst ctx ty in
466 NCicUntrusted.apply_subst_context status ~fix_projections:true
468 let (uri,_,_,_,obj) as okind =
469 constant_for_meta status ctx ty i in
471 NCicEnvironment.check_and_add_obj status okind;
472 let iref = NReference.reference_of_spec uri NReference.Decl in
474 let args = args_for_context ctx in
475 if args = [] then NCic.Const iref
476 else NCic.Appl(NCic.Const iref::args)
478 (* prerr_endline (status#ppterm ctx [] [] iterm); *)
479 let s_entry = i, ([], ctx, iterm, ty)
480 in s_entry::subst,okind::objs
482 Sys.Break as e -> raise e
487 let ground_instances status gl =
488 let _,_,metasenv,subst,_ = status#obj in
489 let subset = menv_closure status gl in
490 let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
492 let submenv = metasenv in
494 let subst, objs = close_metasenv status submenv subst in
498 let (_, ctx, t, _) = List.assoc i subst in
499 noprint (lazy (status#ppterm ctx [] [] t));
501 (fun (uri,_,_,_,_) as obj ->
502 NCicEnvironment.invalidate_item (`Obj (uri, obj)))
507 Not_found -> assert false
511 let replace_meta status i args target =
512 let rec aux k = function
513 (* TODO: local context *)
514 | NCic.Meta (j,lc) when i = j ->
518 List.map (NCicSubstitution.subst_meta status lc) args in
519 NCic.Appl(NCic.Rel k::args))
520 | NCic.Meta (j,lc) as m ->
527 aux k (NCicSubstitution.lift status n t)) l))))
528 | t -> NCicUtils.map status (fun _ k -> k+1) k aux t
533 let close_wrt_metasenv status subst =
535 (fun ty (i,(iattr,ctx,mty)) ->
536 let mty = NCicUntrusted.apply_subst status subst ctx mty in
538 NCicUntrusted.apply_subst_context status ~fix_projections:true
540 let cty = close_wrt_context status mty ctx in
541 let name = "foo"^(string_of_int i) in
542 let ty = NCicSubstitution.lift status 1 ty in
543 let args = args_for_context ~k:1 ctx in
544 (* prerr_endline (status#ppterm ctx [] [] iterm); *)
545 let ty = replace_meta status i args ty
547 NCic.Prod(name,cty,ty))
551 let _,_,metasenv,subst,_ = status#obj in
552 let subset = menv_closure status [g] in
553 let subset = IntSet.remove g subset in
554 let elems = IntSet.elements subset in
555 let _, ctx, ty = NCicUtils.lookup_meta g metasenv in
556 let ty = NCicUntrusted.apply_subst status subst ctx ty in
557 noprint (lazy ("metas in " ^ (status#ppterm ctx [] metasenv ty)));
558 noprint (lazy (String.concat ", " (List.map string_of_int elems)));
559 let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
560 let submenv = List.rev (NCicUntrusted.sort_metasenv status subst submenv) in
562 let submenv = metasenv in
564 let ty = close_wrt_metasenv status subst ty submenv in
565 noprint (lazy (status#ppterm ctx [] [] ty));
569 (****************** smart application ********************)
571 let saturate_to_ref status metasenv subst ctx nref ty =
572 let height = height_of_ref status nref in
573 let rec aux metasenv ty args =
574 let ty,metasenv,moreargs =
575 NCicMetaSubst.saturate status ~delta:height metasenv subst ctx ty 0 in
577 | NCic.Const(NReference.Ref (_,NReference.Def _) as nre)
579 let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in
580 aux metasenv bo (args@moreargs)
581 | NCic.Appl(NCic.Const(NReference.Ref (_,NReference.Def _) as nre)::tl)
583 let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in
584 aux metasenv (NCic.Appl(bo::tl)) (args@moreargs)
585 | _ -> ty,metasenv,(args@moreargs)
589 let smart_apply t unit_eq status g =
590 let n,h,metasenv,subst,o = status#obj in
591 let gname, ctx, gty = List.assoc g metasenv in
592 (* let ggty = mk_cic_term context gty in *)
593 let status, t = disambiguate status ctx t `XTNone in
594 let status,t = term_of_cic_term status t ctx in
595 let _,_,metasenv,subst,_ = status#obj in
596 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
597 let ty,metasenv,args =
600 | NCic.Appl(NCic.Const(nref)::_) ->
601 saturate_to_ref status metasenv subst ctx nref ty
603 NCicMetaSubst.saturate status metasenv subst ctx ty 0 in
604 let metasenv,j,inst,_ = NCicMetaSubst.mk_meta metasenv ctx `IsTerm in
605 let status = status#set_obj (n,h,metasenv,subst,o) in
606 let pterm = if args=[] then t else
608 | NCic.Appl l -> NCic.Appl(l@args)
609 | _ -> NCic.Appl(t::args)
611 noprint(lazy("pterm " ^ (status#ppterm ctx [] [] pterm)));
612 noprint(lazy("pty " ^ (status#ppterm ctx [] [] ty)));
615 NUri.uri_of_string "cic:/matita/basics/logic/eq_coerc.con" in
616 let ref = NReference.reference_of_spec uri (NReference.Def(2)) in
620 NCic.Appl[eq_coerc;ty;NCic.Implicit `Type;pterm;inst] in
621 let smart = mk_cic_term ctx smart in
623 let status = instantiate status g smart in
624 let _,_,metasenv,subst,_ = status#obj in
625 let _,ctx,jty = List.assoc j metasenv in
626 let jty = NCicUntrusted.apply_subst status subst ctx jty in
627 debug_print(lazy("goal " ^ (status#ppterm ctx [] [] jty)));
628 let res = fast_eq_check unit_eq status j in
629 debug_print(lazy("ritorno da fast_eq_check"));
632 | NCicEnvironment.ObjectNotFound s as e ->
633 raise (Error (lazy "eq_coerc non yet defined",Some e))
634 | Error _ as e -> debug_print (lazy "error"); raise e
635 (* FG: for now we catch TypeCheckerFailure; to be understood *)
636 | NCicTypeChecker.TypeCheckerFailure _ ->
637 debug_print (lazy "TypeCheckerFailure");
638 raise (Error (lazy "no proof found",None))
641 let compare_statuses ~past ~present =
642 let _,_,past,_,_ = past#obj in
643 let _,_,present,_,_ = present#obj in
644 List.map fst (List.filter (fun (i,_) -> not(List.mem_assoc i past)) present),
645 List.map fst (List.filter (fun (i,_) -> not (List.mem_assoc i present)) past)
648 (* paramodulation has only an implicit knoweledge of the symmetry of equality;
649 hence it is in trouble in proving (a = b) = (b = a) *)
650 let try_sym tac status g =
651 let sym_eq = Ast.Appl [Ast.Ident("sym_eq",None); Ast.Implicit `Vector] in
652 let _,_,metasenv,subst,_ = status#obj in
653 let _, context, gty = List.assoc g metasenv in
655 NCicParamod.is_equation status metasenv subst context gty
660 let new_status = instantiate_with_ast status g ("",0,sym_eq) in
661 let go, _ = compare_statuses ~past:status ~present:new_status in
662 assert (List.length go = 1);
663 let ng = List.hd go in
668 let smart_apply_tac t s =
669 let unit_eq = index_local_equations s#eq_cache s in
670 NTactics.distribute_tac (try_sym (smart_apply t unit_eq)) s
671 (* NTactics.distribute_tac (smart_apply t unit_eq) s *)
673 let smart_apply_auto t eq_cache =
674 NTactics.distribute_tac (try_sym (smart_apply t eq_cache))
675 (* NTactics.distribute_tac (smart_apply t eq_cache) *)
678 (****************** types **************)
681 type th_cache = (NCic.context * InvRelDiscriminationTree.t) list
683 (* cartesian: term set list -> term list set *)
686 [] -> NDiscriminationTree.TermListSet.empty
688 NDiscriminationTree.TermSet.fold
689 (fun x acc -> NDiscriminationTree.TermListSet.add [x] acc) l NDiscriminationTree.TermListSet.empty
691 let rest = cartesian tl in
692 NDiscriminationTree.TermSet.fold
694 NDiscriminationTree.TermListSet.fold (fun l acc' -> NDiscriminationTree.TermListSet.add (x::l) acc') rest acc
695 ) he NDiscriminationTree.TermListSet.empty
698 (* all_keys_of_cic_type: term -> term set *)
699 let all_keys_of_cic_type status metasenv subst context ty =
701 (* Here we are dropping the metasenv, but this should not raise any
702 exception (hopefully...) *)
704 NCicMetaSubst.saturate status ~delta:max_int metasenv subst context ty 0
710 NCic.Appl (he::tl) ->
713 let wty = NCicReduction.whd status ~delta:0 ~subst context ty in
715 NDiscriminationTree.TermSet.add ty (aux ty)
717 NDiscriminationTree.TermSet.union
718 (NDiscriminationTree.TermSet.add ty (aux ty))
719 (NDiscriminationTree.TermSet.add wty (aux wty))
722 NDiscriminationTree.TermListSet.fold
723 (fun l acc -> NDiscriminationTree.TermSet.add (NCic.Appl l) acc)
724 (cartesian ((NDiscriminationTree.TermSet.singleton he)::tl'))
725 NDiscriminationTree.TermSet.empty
726 | _ -> NDiscriminationTree.TermSet.empty
728 let ty,ity = saturate ty in
729 let wty,iwty = saturate (NCicReduction.whd status ~delta:0 ~subst context ty) in
731 [ity, NDiscriminationTree.TermSet.add ty (aux ty)]
733 [ity, NDiscriminationTree.TermSet.add ty (aux ty) ;
734 iwty, NDiscriminationTree.TermSet.add wty (aux wty) ]
737 let all_keys_of_type status t =
738 let _,_,metasenv,subst,_ = status#obj in
739 let context = ctx_of t in
740 let status, t = apply_subst status context t in
742 all_keys_of_cic_type status metasenv subst context
743 (snd (term_of_cic_term status t context))
747 (fun (intros,keys) ->
749 NDiscriminationTree.TermSet.fold
750 (fun t acc -> Ncic_termSet.add (mk_cic_term context t) acc)
751 keys Ncic_termSet.empty
756 let keys_of_type status orig_ty =
757 (* Here we are dropping the metasenv (in the status), but this should not
758 raise any exception (hopefully...) *)
759 let _, ty, _ = saturate ~delta:max_int status orig_ty in
760 let _, ty = apply_subst status (ctx_of ty) ty in
763 let orig_ty' = NCicTacReduction.normalize ~subst context orig_ty in
764 if orig_ty' <> orig_ty then
765 let ty',_,_= NCicMetaSubst.saturate ~delta:0 metasenv subst context orig_ty' 0 in
771 (*CSC: strange: we keep ty, ty normalized and ty ~delta:(h-1) *)
773 let _, ty = term_of_cic_term status ty (ctx_of ty) in
775 | NCic.Const (NReference.Ref (_,(NReference.Def h | NReference.Fix (_,_,h))))
776 | NCic.Appl (NCic.Const(NReference.Ref(_,(NReference.Def h | NReference.Fix (_,_,h))))::_)
778 let _,ty,_= saturate status ~delta:(h-1) orig_ty in
785 let all_keys_of_term status t =
786 let status, orig_ty = typeof status (ctx_of t) t in
787 all_keys_of_type status orig_ty
790 let keys_of_term status t =
791 let status, orig_ty = typeof status (ctx_of t) t in
792 keys_of_type status orig_ty
795 let mk_th_cache status gl =
797 (fun (status, acc) g ->
798 let gty = get_goalty status g in
799 let ctx = ctx_of gty in
800 noprint(lazy("th cache for: "^ppterm status gty));
801 noprint(lazy("th cache in: "^ppcontext status ctx));
802 if List.mem_assq ctx acc then status, acc else
803 let idx = InvRelDiscriminationTree.empty in
806 (fun (status, i, idx) _ ->
807 let t = mk_cic_term ctx (NCic.Rel i) in
808 let status, keys = keys_of_term status t in
809 noprint(lazy("indexing: "^ppterm status t ^ ": " ^ string_of_int (List.length keys)));
811 List.fold_left (fun idx k ->
812 InvRelDiscriminationTree.index idx k t) idx keys
817 status, (ctx, idx) :: acc)
821 let all_elements ctx cache =
822 let dummy = mk_cic_term ctx (NCic.Meta (0,(0, (NCic.Irl 0)))) in
824 let idx = List.assq ctx cache in
825 Ncic_termSet.elements
826 (InvRelDiscriminationTree.retrieve_unifiables idx dummy)
829 let add_to_th t c ty =
830 let key_c = ctx_of t in
831 if not (List.mem_assq key_c c) then
832 (key_c ,InvRelDiscriminationTree.index
833 InvRelDiscriminationTree.empty ty t ) :: c
835 let rec replace = function
837 | (x, idx) :: tl when x == key_c ->
838 (x, InvRelDiscriminationTree.index idx ty t) :: tl
839 | x :: tl -> x :: replace tl
844 let rm_from_th t c ty =
845 let key_c = ctx_of t in
846 if not (List.mem_assq key_c c) then assert false
848 let rec replace = function
850 | (x, idx) :: tl when x == key_c ->
851 (x, InvRelDiscriminationTree.remove_index idx ty t) :: tl
852 | x :: tl -> x :: replace tl
857 let pp_idx status idx =
858 InvRelDiscriminationTree.iter idx
860 noprint(lazy("K: " ^ NCicInverseRelIndexable.string_of_path k));
862 (fun t -> debug_print(lazy("\t"^ppterm status t)))
866 let pp_th (status: #NTacStatus.pstatus) =
869 noprint(lazy( "-----------------------------------------------"));
870 noprint(lazy( (status#ppcontext ~metasenv:[] ~subst:[] ctx)));
871 noprint(lazy( "||====> "));
875 let search_in_th gty th =
876 let c = ctx_of gty in
877 let rec aux acc = function
878 | [] -> (* Ncic_termSet.elements *) acc
881 let idx = List.assoc(*q*) k th in
882 let acc = Ncic_termSet.union acc
883 (InvRelDiscriminationTree.retrieve_unifiables idx gty)
886 with Not_found -> aux acc tl
888 aux Ncic_termSet.empty c
892 do_types : bool; (* solve goals in Type *)
893 last : bool; (* last goal: take first solution only *)
894 candidates: Ast.term list option;
901 {facts : th_cache; (* positive results *)
902 under_inspection : cic_term list * th_cache; (* to prune looping *)
903 failures : th_cache; (* to avoid repetitions *)
904 unit_eq : NCicParamod.state;
908 let add_to_trace status ~depth cache t =
911 debug_print ~depth (lazy ("Adding to trace: " ^ NotationPp.pp_term status t));
912 {cache with trace = t::cache.trace}
913 | Ast.NCic _ (* local candidate *)
914 | _ -> (*not an application *) cache
916 let pptrace status tr =
917 (lazy ("Proof Trace: " ^ (String.concat ";"
918 (List.map (NotationPp.pp_term status) tr))))
920 let remove_from_trace cache t =
923 (match cache.trace with
924 | _::tl -> {cache with trace = tl}
926 | Ast.NCic _ (* local candidate *)
927 | _ -> (*not an application *) cache *)
930 type goal = int * sort (* goal, depth, sort *)
931 type fail = goal * cic_term
932 type candidate = int * Ast.term (* unique candidate number, candidate *)
934 exception Gaveup of th_cache (* failure cache *)
935 exception Proved of NTacStatus.tac_status * Ast.term list
937 (* let close_failures _ c = c;; *)
938 (* let prunable _ _ _ = false;; *)
939 (* let cache_examine cache gty = `Notfound;; *)
940 (* let put_in_subst s _ _ _ = s;; *)
941 (* let add_to_cache_and_del_from_orlist_if_green_cut _ _ c _ _ o f _ = c, o, f, false ;; *)
942 (* let cache_add_underinspection c _ _ = c;; *)
944 let init_cache ?(facts=[]) ?(under_inspection=[],[])
946 ?(unit_eq=NCicParamod.empty_state)
951 under_inspection = under_inspection;
955 let only signature _context candidate = true
957 (* TASSI: nel trie ci mettiamo solo il body, non il ty *)
959 NCicTypeChecker.typeof ~subst:[] ~metasenv:[] [] candidate
961 let height = fast_height_of_term status candidate_ty in
962 let rc = signature >= height in
964 noprint (lazy ("Filtro: " ^ status#ppterm ~context:[] ~subst:[]
965 ~metasenv:[] candidate ^ ": " ^ string_of_int height))
967 noprint (lazy ("Tengo: " ^ status#ppterm ~context:[] ~subst:[]
968 ~metasenv:[] candidate ^ ": " ^ string_of_int height));
973 let candidate_no = ref 0;;
975 let openg_no status = List.length (head_goals status#stack)
977 let sort_candidates status ctx candidates =
978 let _,_,metasenv,subst,_ = status#obj in
980 let status,ct = disambiguate status ctx ("",0,cand) `XTNone in
981 let status,t = term_of_cic_term status ct ctx in
982 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
983 let res = branch status (mk_cic_term ctx ty) in
984 noprint (lazy ("branch factor for: " ^ (ppterm status ct) ^ " = "
985 ^ (string_of_int res)));
988 let candidates = List.map (fun t -> branch t,t) candidates in
990 List.sort (fun (a,_) (b,_) -> a - b) candidates in
991 let candidates = List.map snd candidates in
992 noprint (lazy ("candidates =\n" ^ (String.concat "\n"
993 (List.map (NotationPp.pp_term status) candidates))));
996 let sort_new_elems l =
997 List.sort (fun (_,s1) (_,s2) -> openg_no s1 - openg_no s2) l
999 let rec stack_goals level gs =
1000 if level = 0 then []
1002 | [] -> assert false
1004 let is_open = function
1005 | (_,Continuationals.Stack.Open i) -> Some i
1006 | (_,Continuationals.Stack.Closed _) -> None
1008 HExtlib.filter_map is_open g @ stack_goals (level-1) s
1011 let open_goals level status = stack_goals level status#stack
1014 let try_candidate ?(smart=0) flags depth status eq_cache ctx t =
1016 let old_og_no = List.length (open_goals (depth+1) status) in
1017 debug_print ~depth (lazy ("try " ^ (string_of_int smart) ^ " : "
1018 ^ (NotationPp.pp_term status) t));
1020 if smart = 0 then NTactics.apply_tac ("",0,t) status
1021 else if smart = 1 then
1022 smart_apply_auto ("",0,t) eq_cache status
1023 else (* smart = 2: both *)
1024 try NTactics.apply_tac ("",0,t) status
1026 smart_apply_auto ("",0,t) eq_cache status
1028 (* FG: this optimization rules out some applications of
1029 * lift_bind (from contribs/lambda_delta/Basic_2/substitution/lift.ma)
1031 (* we compare the expected branching with the actual one and
1032 prune the candidate when the latter is larger. The optimization
1033 is meant to rule out stange applications of flexible terms,
1034 such as the application of eq_f that always succeeds.
1035 There is some gain but less than expected *)
1036 let og_no = List.length (open_goals (depth+1) status) in
1037 let status, cict = disambiguate status ctx ("",0,t) None in
1038 let status,ct = term_of_cic_term status cict ctx in
1039 let _,_,metasenv,subst,_ = status#obj in
1040 let ty = NCicTypeChecker.typeof status subst metasenv ctx ct in
1041 let res = branch status (mk_cic_term ctx ty) in
1042 let diff = og_no - old_og_no in
1043 debug_print (lazy ("expected branching: " ^ (string_of_int res)));
1044 debug_print (lazy ("actual: branching" ^ (string_of_int diff)));
1045 (* some flexibility *)
1046 if og_no - old_og_no > res then
1047 (debug_print (lazy ("branch factor for: " ^ (ppterm status cict) ^ " = "
1048 ^ (string_of_int res) ^ " vs. " ^ (string_of_int og_no)));
1049 debug_print ~depth (lazy "strange application"); None)
1051 *) (incr candidate_no; Some ((!candidate_no,t),status))
1052 with Error (msg,exn) -> debug_print ~depth (lazy "failed"); None
1055 let sort_of status subst metasenv ctx t =
1056 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
1057 let metasenv',ty = NCicUnification.fix_sorts status metasenv subst ty in
1058 assert (metasenv = metasenv');
1059 NCicTypeChecker.typeof status subst metasenv ctx ty
1062 let type0= NUri.uri_of_string ("cic:/matita/pts/Type0.univ")
1065 let perforate_small status subst metasenv context t =
1066 let rec aux = function
1067 | NCic.Appl (hd::tl) ->
1069 let s = sort_of status subst metasenv context t in
1071 | NCic.Sort(NCic.Type [`Type,u])
1072 when u=type0 -> NCic.Meta (0,(0,NCic.Irl 0))
1075 NCic.Appl (hd::List.map map tl)
1081 let get_cands retrieve_for diff empty gty weak_gty =
1082 let cands = retrieve_for gty in
1084 | None -> cands, empty
1086 let more_cands = retrieve_for weak_gty in
1087 cands, diff more_cands cands
1090 let get_candidates ?(smart=true) ~pfailed depth flags status cache signature gty =
1091 let universe = status#auto_cache in
1092 let _,_,metasenv,subst,_ = status#obj in
1093 let context = ctx_of gty in
1094 let _, raw_gty = term_of_cic_term status gty context in
1095 let is_prod, is_eq =
1096 let status, t = term_of_cic_term status gty context in
1097 let t = NCicReduction.whd status subst context t in
1099 | NCic.Prod _ -> true, false
1100 | _ -> false, NCicParamod.is_equation status metasenv subst context t
1102 debug_print ~depth (lazy ("gty:" ^ NTacStatus.ppterm status gty));
1104 NCicParamod.is_equation status metasenv subst context raw_gty
1106 let raw_weak_gty, weak_gty =
1113 perforate_small status subst metasenv context raw_gty in
1114 let weak = mk_cic_term context raw_weak in
1115 noprint ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1116 Some raw_weak, Some (weak)
1120 (* we now compute global candidates *)
1121 let global_cands, smart_global_cands =
1123 let to_ast = function
1124 | NCic.Const r when true
1125 (*is_relevant statistics r*) -> Some (Ast.NRef r)
1126 (* | NCic.Const _ -> None *)
1127 | _ -> assert false in
1129 to_ast (NDiscriminationTree.TermSet.elements s) in
1132 (NDiscriminationTree.DiscriminationTree.retrieve_unifiables universe)
1133 NDiscriminationTree.TermSet.diff
1134 NDiscriminationTree.TermSet.empty
1135 raw_gty raw_weak_gty in
1137 (* we now compute local candidates *)
1138 let local_cands,smart_local_cands =
1141 let _status, t = term_of_cic_term status t context
1143 List.map to_ast (Ncic_termSet.elements s) in
1146 (fun ty -> search_in_th ty cache)
1147 Ncic_termSet.diff Ncic_termSet.empty gty weak_gty in
1149 (* we now splits candidates in facts or not facts *)
1150 let test = is_a_fact_ast status subst metasenv context in
1151 let by,given_candidates =
1152 match flags.candidates with
1154 | None -> false, [] in
1155 (* we compute candidates to be applied in normal mode, splitted in
1156 facts and not facts *)
1157 let candidates_facts,candidates_other =
1158 let gl1,gl2 = List.partition test global_cands in
1159 let ll1,ll2 = List.partition test local_cands in
1160 (* if the goal is an equation and paramodulation did not fail
1161 we avoid to apply unit equalities; refl is an
1162 exception since it prompts for convertibility *)
1163 let l1 = if is_eq && (not pfailed)
1164 then [Ast.Ident("refl",None)] else gl1@ll1 in
1166 (* if smart given candidates are applied in smart mode *)
1167 if by && smart then ll2
1168 else if by then given_candidates@ll2
1172 (* we now compute candidates to be applied in smart mode, splitted in
1173 facts and not facts *)
1174 let smart_candidates_facts, smart_candidates_other =
1175 if is_prod || not(smart) then [],[]
1177 let sgl1,sgl2 = List.partition test smart_global_cands in
1178 let sll1,sll2 = List.partition test smart_local_cands in
1179 let l1 = if is_eq then [] else sgl1@sll1 in
1181 if by && smart then given_candidates@sll2
1182 else if by then sll2
1187 smart_candidates_facts,
1188 sort_candidates status context (candidates_other),
1189 sort_candidates status context (smart_candidates_other)
1192 let applicative_case ~pfailed depth signature status flags gty cache =
1193 app_counter:= !app_counter+1;
1194 let _,_,metasenv,subst,_ = status#obj in
1195 let context = ctx_of gty in
1196 let tcache = cache.facts in
1197 let is_prod, is_eq =
1198 let status, t = term_of_cic_term status gty context in
1199 let t = NCicReduction.whd status subst context t in
1201 | NCic.Prod _ -> true, false
1202 | _ -> false, NCicParamod.is_equation status metasenv subst context t
1204 debug_print ~depth (lazy (string_of_bool is_eq));
1206 let candidates_facts, smart_candidates_facts,
1207 candidates_other, smart_candidates_other =
1208 get_candidates ~smart:true ~pfailed depth
1209 flags status tcache signature gty
1211 let sm = if is_eq || is_prod then 0 else 2 in
1212 let sm1 = if flags.last then 2 else 0 in
1213 let maxd = (depth + 1 = flags.maxdepth) in
1214 let try_candidates only_one sm acc candidates =
1217 if (only_one && (elems <> [])) then elems
1219 match try_candidate (~smart:sm)
1220 flags depth status cache.unit_eq context cand with
1222 | Some x -> x::elems)
1225 (* if the goal is the last one we stop at the first fact *)
1226 let elems = try_candidates flags.last sm [] candidates_facts in
1227 (* now we add smart_facts *)
1228 let elems = try_candidates flags.last sm elems smart_candidates_facts in
1229 (* if we are at maxdepth and the goal is not a product we are done
1230 similarly, if the goal is the last one and we already found a
1232 if (maxd && not(is_prod)) || (flags.last && elems<>[]) then elems
1234 let elems = try_candidates false 2 elems candidates_other in
1235 debug_print ~depth (lazy ("not facts: try smart application"));
1236 try_candidates false 2 elems smart_candidates_other
1242 (* gty is supposed to be meta-closed *)
1243 let is_subsumed depth filter_depth status gty cache =
1244 if cache=[] then false else (
1245 debug_print ~depth (lazy("Subsuming " ^ (ppterm status gty)));
1246 let n,h,metasenv,subst,obj = status#obj in
1247 let ctx = ctx_of gty in
1248 let _ , raw_gty = term_of_cic_term status gty ctx in
1249 let target = NCicSubstitution.lift status 1 raw_gty in
1250 (* we compute candidates using the perforated type *)
1257 perforate_small status subst metasenv ctx raw_gty in
1258 let weak = mk_cic_term ctx raw_weak in
1259 debug_print ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1263 (* candidates must only be searched w.r.t the given context *)
1266 let idx = List.assq ctx cache in
1269 Ncic_termSet.elements
1270 (InvRelDiscriminationTree.retrieve_unifiables idx weak)
1272 with Not_found -> []
1274 (* this is a dirty trick: the first argument of an application is used
1275 to remember at which depth a goal failed *)
1277 let ctx = ctx_of t in
1278 let _, src = term_of_cic_term status t ctx in
1280 | NCic.Appl [NCic.Implicit (`Typeof d); t]
1281 when d <= depth -> Some (mk_cic_term ctx t)
1284 if filter_depth then HExtlib.filter_map filter candidates else candidates in
1286 (lazy ("failure candidates: " ^ string_of_int (List.length candidates)));
1290 let _ , source = term_of_cic_term status t ctx in
1292 NCic.Prod("foo",source,target) in
1293 let metasenv,j,_,_ =
1294 NCicMetaSubst.mk_meta
1295 metasenv ctx ~with_type:implication `IsType in
1296 let status = status#set_obj (n,h,metasenv,subst,obj) in
1297 let status = status#set_stack [([1,Open j],[],[],`NoTag)] in
1299 let status = NTactics.intro_tac "foo" status in
1301 NTactics.apply_tac ("",0,Ast.NCic (NCic.Rel 1)) status
1303 if (head_goals status#stack = []) then raise Found
1308 with Found -> debug_print ~depth (lazy "success");true)
1311 let rec guess_name name ctx =
1312 if name = "_" then guess_name "auto" ctx else
1313 if not (List.mem_assoc name ctx) then name else
1314 guess_name (name^"'") ctx
1317 let is_prod status =
1318 let _, ctx, gty = current_goal status in
1319 let status, gty = apply_subst status ctx gty in
1320 let _, raw_gty = term_of_cic_term status gty ctx in
1322 | NCic.Prod (name,src,_) ->
1323 let status, src = whd status ~delta:0 ctx (mk_cic_term ctx src) in
1324 (match snd (term_of_cic_term status src ctx) with
1325 | NCic.Const(NReference.Ref (_,NReference.Ind _) as r)
1326 | NCic.Appl (NCic.Const(NReference.Ref (_,NReference.Ind _) as r)::_) ->
1327 let _,_,itys,_,_ = NCicEnvironment.get_checked_indtys status r in
1329 (* | [_,_,_,[_;_]] con nat va, ovviamente, in loop *)
1331 | [_,_,_,[]] -> `Inductive (guess_name name ctx)
1332 | _ -> `Some (guess_name name ctx))
1333 | _ -> `Some (guess_name name ctx))
1336 let intro ~depth status facts name =
1337 let status = NTactics.intro_tac name status in
1338 let _, ctx, ngty = current_goal status in
1339 let t = mk_cic_term ctx (NCic.Rel 1) in
1340 let status, keys = keys_of_term status t in
1341 let facts = List.fold_left (add_to_th t) facts keys in
1342 debug_print ~depth (lazy ("intro: "^ name));
1343 (* unprovability is not stable w.r.t introduction *)
1347 let rec intros_facts ~depth status facts =
1348 if List.length (head_goals status#stack) <> 1 then status, facts else
1349 match is_prod status with
1353 intro ~depth status facts name
1354 in intros_facts ~depth status facts
1355 (* | `Inductive name ->
1356 let status = NTactics.case1_tac name status in
1357 intros_facts ~depth status facts *)
1358 | _ -> status, facts
1361 let intros ~depth status cache =
1362 match is_prod status with
1365 let trace = cache.trace in
1367 intros_facts ~depth status cache.facts
1369 if head_goals status#stack = [] then
1370 let status = NTactics.merge_tac status in
1371 [(0,Ast.Ident("__intros",None)),status], cache
1373 (* we reindex the equation from scratch *)
1374 let unit_eq = index_local_equations status#eq_cache status in
1375 let status = NTactics.merge_tac status in
1376 [(0,Ast.Ident("__intros",None)),status],
1377 init_cache ~facts ~unit_eq () ~trace
1381 let reduce ~whd ~depth status g =
1382 let n,h,metasenv,subst,o = status#obj in
1383 let attr, ctx, ty = NCicUtils.lookup_meta g metasenv in
1384 let ty = NCicUntrusted.apply_subst status subst ctx ty in
1386 (if whd then NCicReduction.whd else NCicTacReduction.normalize) status ~subst ctx ty
1391 (lazy ("reduced to: "^ status#ppterm ctx subst metasenv ty'));
1393 (g,(attr,ctx,ty'))::(List.filter (fun (i,_) -> i<>g) metasenv)
1395 let status = status#set_obj (n,h,metasenv,subst,o) in
1396 (* we merge to gain a depth level; the previous goal level should
1398 let status = NTactics.merge_tac status in
1400 [(!candidate_no,Ast.Ident("__whd",None)),status])
1403 let is_meta status gty =
1404 let _, ty = term_of_cic_term status gty (ctx_of gty) in
1406 | NCic.Meta _ -> true
1410 let do_something signature flags status g depth gty cache =
1411 (* if the goal is meta we close it with I:True. This should work
1412 thanks to the toplogical sorting of goals. *)
1413 if is_meta status gty then
1414 let t = Ast.Ident("I",None) in
1415 debug_print (lazy ("using default term" ^ (NotationPp.pp_term status) t));
1416 let s = NTactics.apply_tac ("",0,t) status in
1419 let l0, cache = intros ~depth status cache in
1420 if l0 <> [] then l0, cache
1423 let l = reduce ~whd:true ~depth status g in
1424 (* if l <> [] then l,cache else *)
1425 (* backward aplications *)
1430 ((!candidate_no,Ast.Ident("__paramod",None)),s))
1431 (auto_eq_check cache.unit_eq status)
1434 if ((l1 <> []) && flags.last) then [] else
1435 applicative_case ~pfailed:(l1=[]) depth signature status flags gty cache
1439 (fun ((_,t),_) -> toref incr_nominations statistics t) l2;
1440 (* states in l1 have have an empty set of subgoals: no point to sort them *)
1442 (lazy ("alternatives = " ^ (string_of_int (List.length (l1@l@l2)))));
1443 (* we order alternatives w.r.t the number of subgoals they open *)
1444 l1 @ (sort_new_elems l2) @ l, cache
1447 let pp_goal = function
1448 | (_,Continuationals.Stack.Open i)
1449 | (_,Continuationals.Stack.Closed i) -> string_of_int i
1452 let pp_goals status l =
1456 let gty = get_goalty status i in
1457 NTacStatus.ppterm status gty)
1464 let compare = Pervasives.compare
1468 module MS = HTopoSort.Make(M)
1471 let sort_tac status =
1473 match status#stack with
1474 | [] -> assert false
1475 | (goals, t, k, tag) :: s ->
1476 let g = head_goals status#stack in
1478 (List.rev (MS.topological_sort g (deps status))) in
1479 noprint (lazy ("old g = " ^
1480 String.concat "," (List.map string_of_int g)));
1481 noprint (lazy ("sorted goals = " ^
1482 String.concat "," (List.map string_of_int sortedg)));
1483 let is_it i = function
1484 | (_,Continuationals.Stack.Open j )
1485 | (_,Continuationals.Stack.Closed j ) -> i = j
1488 List.map (fun i -> List.find (is_it i) goals) sortedg
1490 (sorted_goals, t, k, tag) :: s
1492 status#set_stack gstatus
1495 let clean_up_tac status =
1497 match status#stack with
1498 | [] -> assert false
1499 | (g, t, k, tag) :: s ->
1500 let is_open = function
1501 | (_,Continuationals.Stack.Open _) -> true
1502 | (_,Continuationals.Stack.Closed _) -> false
1504 let g' = List.filter is_open g in
1505 (g', t, k, tag) :: s
1507 status#set_stack gstatus
1510 let focus_tac focus status =
1512 match status#stack with
1513 | [] -> assert false
1514 | (g, t, k, tag) :: s ->
1515 let in_focus = function
1516 | (_,Continuationals.Stack.Open i)
1517 | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1519 let focus,others = List.partition in_focus g
1521 (* we need to mark it as a BranchTag, otherwise cannot merge later *)
1522 (focus,[],[],`BranchTag) :: (others, t, k, tag) :: s
1524 status#set_stack gstatus
1527 let deep_focus_tac level focus status =
1528 let in_focus = function
1529 | (_,Continuationals.Stack.Open i)
1530 | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1532 let rec slice level gs =
1533 if level = 0 then [],[],gs else
1535 | [] -> assert false
1536 | (g, t, k, tag) :: s ->
1537 let f,o,gs = slice (level-1) s in
1538 let f1,o1 = List.partition in_focus g
1540 (f1,[],[],`BranchTag)::f, (o1, t, k, tag)::o, gs
1543 let f,o,s = slice level status#stack in f@o@s
1545 status#set_stack gstatus
1548 let move_to_side level status =
1549 match status#stack with
1550 | [] -> assert false
1552 let is_open = function
1553 | (_,Continuationals.Stack.Open i) -> Some i
1554 | (_,Continuationals.Stack.Closed _) -> None
1556 let others = menv_closure status (stack_goals (level-1) tl) in
1557 List.for_all (fun i -> IntSet.mem i others)
1558 (HExtlib.filter_map is_open g)
1560 let top_cache ~depth top status cache =
1562 let unit_eq = index_local_equations status#eq_cache status in
1563 {cache with unit_eq = unit_eq}
1566 let rec auto_clusters ?(top=false)
1567 flags signature cache depth status : unit =
1568 debug_print ~depth (lazy ("entering auto clusters at depth " ^
1569 (string_of_int depth)));
1570 debug_print ~depth (pptrace status cache.trace);
1571 (* ignore(Unix.select [] [] [] 0.01); *)
1572 let status = clean_up_tac status in
1573 let goals = head_goals status#stack in
1575 if depth = 0 then raise (Proved (status, cache.trace))
1577 let status = NTactics.merge_tac status in
1579 let l,tree = cache.under_inspection in
1581 | [] -> cache (* possible because of intros that cleans the cache *)
1582 | a::tl -> let tree = rm_from_th a tree a in
1583 {cache with under_inspection = tl,tree}
1585 auto_clusters flags signature cache (depth-1) status
1586 else if List.length goals < 2 then
1587 let cache = top_cache ~depth top status cache in
1588 auto_main flags signature cache depth status
1590 let all_goals = open_goals (depth+1) status in
1591 debug_print ~depth (lazy ("goals = " ^
1592 String.concat "," (List.map string_of_int all_goals)));
1593 let classes = HExtlib.clusters (deps status) all_goals in
1594 (* if any of the classes exceed maxwidth we fail *)
1597 if List.length gl > flags.maxwidth then
1599 debug_print ~depth (lazy "FAIL GLOBAL WIDTH");
1600 HLog.warn (sprintf "global width (%u) exceeded: %u"
1601 flags.maxwidth (List.length gl));
1602 raise (Gaveup cache.failures)
1603 end else ()) classes;
1604 if List.length classes = 1 then
1606 {flags with last = (List.length all_goals = 1)} in
1607 (* no need to cluster *)
1608 let cache = top_cache ~depth top status cache in
1609 auto_main flags signature cache depth status
1611 let classes = if top then List.rev classes else classes in
1617 ("cluster:" ^ String.concat "," (List.map string_of_int l)))
1619 (* we now process each cluster *)
1620 let status,cache,b =
1622 (fun (status,cache,b) gl ->
1624 {flags with last = (List.length gl = 1)} in
1625 let lold = List.length status#stack in
1626 debug_print ~depth (lazy ("stack length = " ^
1627 (string_of_int lold)));
1628 let fstatus = deep_focus_tac (depth+1) gl status in
1629 let cache = top_cache ~depth top fstatus cache in
1631 debug_print ~depth (lazy ("focusing on" ^
1632 String.concat "," (List.map string_of_int gl)));
1633 auto_main flags signature cache depth fstatus; assert false
1635 | Proved(status,trace) ->
1636 let status = NTactics.merge_tac status in
1637 let cache = {cache with trace = trace} in
1638 let lnew = List.length status#stack in
1639 assert (lold = lnew);
1641 | Gaveup failures when top ->
1642 let cache = {cache with failures = failures} in
1645 (status,cache,false) classes
1647 let rec final_merge n s =
1648 if n = 0 then s else final_merge (n-1) (NTactics.merge_tac s)
1649 in let status = final_merge depth status
1650 in if b then raise (Proved(status,cache.trace)) else raise (Gaveup cache.failures)
1654 (* BRAND NEW VERSION *)
1655 auto_main flags signature cache depth status: unit =
1656 debug_print ~depth (lazy "entering auto main");
1657 debug_print ~depth (pptrace status cache.trace);
1658 debug_print ~depth (lazy ("stack length = " ^
1659 (string_of_int (List.length status#stack))));
1660 (* ignore(Unix.select [] [] [] 0.01); *)
1661 let status = sort_tac (clean_up_tac status) in
1662 let goals = head_goals status#stack in
1664 | [] when depth = 0 -> raise (Proved (status,cache.trace))
1666 let status = NTactics.merge_tac status in
1668 let l,tree = cache.under_inspection in
1670 | [] -> cache (* possible because of intros that cleans the cache *)
1671 | a::tl -> let tree = rm_from_th a tree a in
1672 {cache with under_inspection = tl,tree}
1674 auto_clusters flags signature cache (depth-1) status
1676 if depth > 0 && move_to_side depth status
1678 let status = NTactics.merge_tac status in
1680 let l,tree = cache.under_inspection in
1682 | [] -> cache (* possible because of intros that cleans the cache*)
1683 | a::tl -> let tree = rm_from_th a tree a in
1684 {cache with under_inspection = tl,tree}
1686 auto_clusters flags signature cache (depth-1) status
1688 let ng = List.length goals in
1689 (* moved inside auto_clusters *)
1690 if ng > flags.maxwidth then begin
1691 debug_print ~depth (lazy "FAIL LOCAL WIDTH");
1692 HLog.warn (sprintf "local width (%u) exceeded: %u"
1694 raise (Gaveup cache.failures)
1695 end else if depth = flags.maxdepth then
1696 raise (Gaveup cache.failures)
1698 let status = NTactics.branch_tac ~force:true status in
1699 let g,gctx, gty = current_goal status in
1700 let ctx,ty = close status g in
1701 let closegty = mk_cic_term ctx ty in
1702 let status, gty = apply_subst status gctx gty in
1703 debug_print ~depth (lazy("Attacking goal " ^
1704 string_of_int g ^ " : "^ppterm status gty));
1705 debug_print ~depth (lazy ("current failures: " ^
1706 string_of_int (List.length (all_elements ctx cache.failures))));
1708 let _,_,metasenv,subst,_ = status#obj in
1709 NCicParamod.is_equation status metasenv subst ctx ty in
1710 (* if the goal is an equality we artificially raise its depth up to
1711 flags.maxdepth - 1 *)
1712 if (not flags.last && is_eq && (depth < (flags.maxdepth -2))) then
1713 (* for efficiency reasons, in this case we severely cripple the
1715 (debug_print ~depth (lazy ("RAISING DEPTH TO " ^ string_of_int (depth+1)));
1716 auto_main flags signature cache (depth+1) status)
1717 (* check for loops *)
1718 else if is_subsumed depth false status closegty (snd cache.under_inspection) then
1719 (debug_print ~depth (lazy "SUBSUMED");
1720 raise (Gaveup cache.failures))
1721 (* check for failures *)
1722 else if is_subsumed depth true status closegty cache.failures then
1723 (debug_print ~depth (lazy "ALREADY MET");
1724 raise (Gaveup cache.failures))
1726 let new_sig = height_of_goal g status in
1727 if new_sig < signature then
1728 (debug_print ~depth (lazy ("news = " ^ (string_of_int new_sig)));
1729 debug_print ~depth (lazy ("olds = " ^ (string_of_int signature))));
1730 let alternatives, cache =
1731 do_something signature flags status g depth gty cache in
1734 let l,tree = cache.under_inspection in
1735 let l,tree = closegty::l, add_to_th closegty tree closegty in
1736 {cache with under_inspection = l,tree}
1740 (fun allfailures ((_,t),status) ->
1742 (lazy ("(re)considering goal " ^
1743 (string_of_int g) ^" : "^ppterm status gty));
1744 debug_print (~depth:depth)
1745 (lazy ("Case: " ^ NotationPp.pp_term status t));
1747 if t=Ast.Ident("__whd",None) ||
1748 t=Ast.Ident("__intros",None)
1750 else depth+1,loop_cache in
1751 let cache = add_to_trace status ~depth cache t in
1752 let cache = {cache with failures = allfailures} in
1754 auto_clusters flags signature cache depth status;
1757 debug_print ~depth (lazy "Failed");
1759 cache.failures alternatives in
1763 let dty = NCic.Appl [NCic.Implicit (`Typeof depth); ty] in
1766 (*prerr_endline ("FAILURE : " ^ ppterm status gty);*)
1767 add_to_th newfail failures closegty
1769 debug_print ~depth (lazy "no more candidates");
1770 raise (Gaveup failures)
1773 let int name l def =
1774 try int_of_string (List.assoc name l)
1775 with Failure _ | Not_found -> def
1778 module AstSet = Set.Make(struct type t = Ast.term let compare = compare end)
1780 let cleanup_trace s trace =
1781 (* removing duplicates *)
1784 (fun acc t -> AstSet.add t acc)
1785 AstSet.empty trace in
1786 let trace = AstSet.elements trace_set
1787 (* filtering facts *)
1791 | Ast.NRef (NReference.Ref (u,_)) -> not (is_a_fact_obj s u)
1795 let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =
1796 let oldstatus = status in
1797 let status = (status:> NTacStatus.tac_status) in
1798 let goals = head_goals status#stack in
1799 let status, facts = mk_th_cache status goals in
1800 (* let unit_eq = index_local_equations status#eq_cache status in *)
1801 let cache = init_cache ~facts () in
1802 (* pp_th status facts; *)
1804 NDiscriminationTree.DiscriminationTree.iter status#auto_cache (fun p t ->
1806 NDiscriminationTree.NCicIndexable.string_of_path p ^ " |--> " ^
1807 String.concat "\n " (List.map (
1808 status#ppterm ~metasenv:[] ~context:[] ~subst:[])
1809 (NDiscriminationTree.TermSet.elements t))
1817 (* FG: `XTSort here? *)
1818 let status, res = disambiguate status [] t `XTNone in
1819 let _,res = term_of_cic_term status res (ctx_of res)
1821 in Some (List.map to_Ast l)
1823 let depth = int "depth" flags 3 in
1824 let size = int "size" flags 10 in
1825 let width = int "width" flags 4 (* (3+List.length goals)*) in
1827 (* let goals = List.map (fun i -> (i,P)) goals in *)
1828 let signature = height_of_goals status in
1831 candidates = candidates;
1837 let initial_time = Unix.gettimeofday() in
1842 ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1844 ("Applicative nodes:"^string_of_int !app_counter));
1845 raise (Error (lazy "auto gave up", None)))
1847 let _ = debug_print (lazy("\n\nRound "^string_of_int x^"\n")) in
1848 let flags = { flags with maxdepth = x }
1850 try auto_clusters (~top:true) flags signature cache 0 status;assert false
1852 try auto_main flags signature cache 0 status;assert false
1855 | Gaveup _ -> up_to (x+1) y
1856 | Proved (s,trace) ->
1857 debug_print (lazy ("proved at depth " ^ string_of_int x));
1858 List.iter (toref incr_uses statistics) trace;
1859 let trace = cleanup_trace s trace in
1860 let _ = debug_print (pptrace status trace) in
1863 | (g,t,k,f) :: rest -> (filter_open g,t,k,f):: rest
1866 let s = s#set_stack stack in
1868 oldstatus#set_status s
1870 let s = up_to depth depth in
1871 debug_print (print_stat status statistics);
1873 ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1875 ("Applicative nodes:"^string_of_int !app_counter));
1879 let auto_tac ~params:(_,flags as params) ?trace_ref =
1880 if List.mem_assoc "demod" flags then
1882 else if List.mem_assoc "paramod" flags then
1884 else if List.mem_assoc "fast_paramod" flags then
1885 fast_eq_check_tac ~params
1886 else auto_tac ~params ?trace_ref