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 ?(flag=false) status =
297 NCicParamod.empty_state
299 noprint (lazy "indexing equations");
300 let open_goals = head_goals status#stack in
301 let open_goal = List.hd open_goals in
302 let ngty = get_goalty status open_goal in
303 let _,_,metasenv,subst,_ = status#obj in
304 let ctx = apply_subst_context ~fix_projections:true status (ctx_of ngty) in
309 let t = NCic.Rel !c in
311 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
312 if is_a_fact status (mk_cic_term ctx ty) then
313 (debug_print(lazy("eq indexing " ^ (status#ppterm ctx subst metasenv ty)));
314 NCicParamod.forward_infer_step status metasenv subst ctx eq_cache t ty)
316 (noprint (lazy ("not a fact: " ^ (status#ppterm ctx subst metasenv ty)));
319 | NCicTypeChecker.TypeCheckerFailure _
320 | NCicTypeChecker.AssertFailure _ -> eq_cache)
325 let index_local_equations2 eq_cache status open_goal lemmas ?(flag=false) nohyps =
327 NCicParamod.empty_state
329 noprint (lazy "indexing equations");
330 let eq_cache,lemmas =
333 | Some l -> NCicParamod.empty_state,l
335 let ngty = get_goalty status open_goal in
336 let _,_,metasenv,subst,_ = status#obj in
337 let ctx = apply_subst_context ~fix_projections:true status (ctx_of ngty) in
340 (fun (status,lemmas) l ->
341 let status,l = NTacStatus.disambiguate status ctx l `XTNone in
342 let status,l = NTacStatus.term_of_cic_term status l ctx in
344 (status,[]) lemmas in
345 let local_equations =
346 if nohyps then [] else
347 List.map (fun i -> NCic.Rel (i + 1))
348 (HExtlib.list_seq 1 (List.length ctx)) in
349 let lemmas = lemmas @ local_equations in
353 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
354 if is_a_fact status (mk_cic_term ctx ty) then
355 (debug_print(lazy("eq indexing " ^ (status#ppterm ctx subst metasenv ty)));
356 NCicParamod.forward_infer_step status metasenv subst ctx eq_cache t ty)
358 (noprint (lazy ("not a fact: " ^ (status#ppterm ctx subst metasenv ty)));
361 | NCicTypeChecker.TypeCheckerFailure _
362 | NCicTypeChecker.AssertFailure _ -> eq_cache)
367 let fast_eq_check_tac ~params s =
368 let unit_eq = index_local_equations s#eq_cache s in
369 dist_fast_eq_check unit_eq s
372 let paramod eq_cache status goal =
373 match solve NCicParamod.paramod status eq_cache goal with
374 | [] -> raise (Error (lazy "no proof found",None))
378 let paramod_tac ~params s =
379 let unit_eq = index_local_equations s#eq_cache s in
380 NTactics.distribute_tac (paramod unit_eq) s
383 let demod eq_cache status goal =
384 match solve NCicParamod.demod status eq_cache goal with
385 | [] -> raise (Error (lazy "no progress",None))
389 let demod_tac ~params s =
391 index_local_equations2 s#eq_cache s i (fst params)
392 (List.mem_assoc "nohyps" (snd params))
394 NTactics.distribute_tac (fun s i -> demod (unit_eq s i) s i) s
398 let fast_eq_check_tac_all ~params eq_cache status =
399 let g,_,_ = current_goal status in
400 let allstates = fast_eq_check_all status eq_cache g in
401 let pseudo_low_tac s _ _ = s in
402 let pseudo_low_tactics =
403 List.map pseudo_low_tac allstates
405 List.map (fun f -> NTactics.distribute_tac f status) pseudo_low_tactics
410 let demod status eq_cache goal =
411 let n,h,metasenv,subst,o = status#obj in
412 let gname, ctx, gty = List.assoc goal metasenv in
413 let gty = NCicUntrusted.apply_subst subst ctx gty in
415 let demod_tac ~params s =
416 let unit_eq = index_local_equations s#eq_cache s in
417 dist_fast_eq_check unit_eq s
420 (*************** subsumption ****************)
422 let close_wrt_context status =
426 | name, NCic.Decl t -> NCic.Prod(name,t,ty)
427 | name, NCic.Def(bo, _) -> NCicSubstitution.subst status bo ty)
430 let args_for_context ?(k=1) ctx =
433 (fun (n,l) ctx_entry ->
435 | name, NCic.Decl t -> n+1,NCic.Rel(n)::l
436 | name, NCic.Def(bo, _) -> n+1,l)
440 let constant_for_meta status ctx ty i =
441 let name = "cic:/foo"^(string_of_int i)^".con" in
442 let uri = NUri.uri_of_string name in
443 let ty = close_wrt_context status ty ctx in
444 (* prerr_endline (status#ppterm [] [] [] ty); *)
445 let attr = (`Generated,`Definition,`Local) in
446 let obj = NCic.Constant([],name,None,ty,attr) in
447 (* Constant of relevance * string * term option * term * c_attr *)
451 let refresh metasenv =
453 (fun (metasenv,subst) (i,(iattr,ctx,ty)) ->
454 let ikind = NCicUntrusted.kind_of_meta iattr in
455 let metasenv,j,instance,ty =
456 NCicMetaSubst.mk_meta ~attrs:iattr
457 metasenv ctx ~with_type:ty ikind in
458 let s_entry = i,(iattr, ctx, instance, ty) in
459 let metasenv = List.filter (fun x,_ -> i <> x) metasenv in
460 metasenv,s_entry::subst)
461 (metasenv,[]) metasenv
463 (* close metasenv returns a ground instance of all the metas in the
464 metasenv, insantiatied with axioms, and the list of these axioms *)
465 let close_metasenv status metasenv subst =
467 let metasenv = NCicUntrusted.apply_subst_metasenv subst metasenv in
469 let metasenv = NCicUntrusted.sort_metasenv status subst metasenv in
471 (fun (subst,objs) (i,(iattr,ctx,ty)) ->
472 let ty = NCicUntrusted.apply_subst status subst ctx ty in
474 NCicUntrusted.apply_subst_context status ~fix_projections:true
476 let (uri,_,_,_,obj) as okind =
477 constant_for_meta status ctx ty i in
479 NCicEnvironment.check_and_add_obj status okind;
480 let iref = NReference.reference_of_spec uri NReference.Decl in
482 let args = args_for_context ctx in
483 if args = [] then NCic.Const iref
484 else NCic.Appl(NCic.Const iref::args)
486 (* prerr_endline (status#ppterm ctx [] [] iterm); *)
487 let s_entry = i, ([], ctx, iterm, ty)
488 in s_entry::subst,okind::objs
490 Sys.Break as e -> raise e
495 let ground_instances status gl =
496 let _,_,metasenv,subst,_ = status#obj in
497 let subset = menv_closure status gl in
498 let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
500 let submenv = metasenv in
502 let subst, objs = close_metasenv status submenv subst in
506 let (_, ctx, t, _) = List.assoc i subst in
507 noprint (lazy (status#ppterm ctx [] [] t));
509 (fun (uri,_,_,_,_) as obj ->
510 NCicEnvironment.invalidate_item (`Obj (uri, obj)))
515 Not_found -> assert false
519 let replace_meta status i args target =
520 let rec aux k = function
521 (* TODO: local context *)
522 | NCic.Meta (j,lc) when i = j ->
526 List.map (NCicSubstitution.subst_meta status lc) args in
527 NCic.Appl(NCic.Rel k::args))
528 | NCic.Meta (j,lc) as m ->
535 aux k (NCicSubstitution.lift status n t)) l))))
536 | t -> NCicUtils.map status (fun _ k -> k+1) k aux t
541 let close_wrt_metasenv status subst =
543 (fun ty (i,(iattr,ctx,mty)) ->
544 let mty = NCicUntrusted.apply_subst status subst ctx mty in
546 NCicUntrusted.apply_subst_context status ~fix_projections:true
548 let cty = close_wrt_context status mty ctx in
549 let name = "foo"^(string_of_int i) in
550 let ty = NCicSubstitution.lift status 1 ty in
551 let args = args_for_context ~k:1 ctx in
552 (* prerr_endline (status#ppterm ctx [] [] iterm); *)
553 let ty = replace_meta status i args ty
555 NCic.Prod(name,cty,ty))
559 let _,_,metasenv,subst,_ = status#obj in
560 let subset = menv_closure status [g] in
561 let subset = IntSet.remove g subset in
562 let elems = IntSet.elements subset in
563 let _, ctx, ty = NCicUtils.lookup_meta g metasenv in
564 let ty = NCicUntrusted.apply_subst status subst ctx ty in
565 noprint (lazy ("metas in " ^ (status#ppterm ctx [] metasenv ty)));
566 noprint (lazy (String.concat ", " (List.map string_of_int elems)));
567 let submenv = List.filter (fun (x,_) -> IntSet.mem x subset) metasenv in
568 let submenv = List.rev (NCicUntrusted.sort_metasenv status subst submenv) in
570 let submenv = metasenv in
572 let ty = close_wrt_metasenv status subst ty submenv in
573 noprint (lazy (status#ppterm ctx [] [] ty));
577 (****************** smart application ********************)
579 let saturate_to_ref status metasenv subst ctx nref ty =
580 let height = height_of_ref status nref in
581 let rec aux metasenv ty args =
582 let ty,metasenv,moreargs =
583 NCicMetaSubst.saturate status ~delta:height metasenv subst ctx ty 0 in
585 | NCic.Const(NReference.Ref (_,NReference.Def _) as nre)
587 let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in
588 aux metasenv bo (args@moreargs)
589 | NCic.Appl(NCic.Const(NReference.Ref (_,NReference.Def _) as nre)::tl)
591 let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def status nre in
592 aux metasenv (NCic.Appl(bo::tl)) (args@moreargs)
593 | _ -> ty,metasenv,(args@moreargs)
597 let smart_apply t unit_eq status g =
598 let n,h,metasenv,subst,o = status#obj in
599 let gname, ctx, gty = List.assoc g metasenv in
600 (* let ggty = mk_cic_term context gty in *)
601 let status, t = disambiguate status ctx t `XTNone in
602 let status,t = term_of_cic_term status t ctx in
603 let _,_,metasenv,subst,_ = status#obj in
604 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
605 let ty,metasenv,args =
608 | NCic.Appl(NCic.Const(nref)::_) ->
609 saturate_to_ref status metasenv subst ctx nref ty
611 NCicMetaSubst.saturate status metasenv subst ctx ty 0 in
612 let metasenv,j,inst,_ = NCicMetaSubst.mk_meta metasenv ctx `IsTerm in
613 let status = status#set_obj (n,h,metasenv,subst,o) in
614 let pterm = if args=[] then t else
616 | NCic.Appl l -> NCic.Appl(l@args)
617 | _ -> NCic.Appl(t::args)
619 noprint(lazy("pterm " ^ (status#ppterm ctx [] [] pterm)));
620 noprint(lazy("pty " ^ (status#ppterm ctx [] [] ty)));
623 NUri.uri_of_string "cic:/matita/basics/logic/eq_coerc.con" in
624 let ref = NReference.reference_of_spec uri (NReference.Def(2)) in
628 NCic.Appl[eq_coerc;ty;NCic.Implicit `Type;pterm;inst] in
629 let smart = mk_cic_term ctx smart in
631 let status = instantiate status g smart in
632 let _,_,metasenv,subst,_ = status#obj in
633 let _,ctx,jty = List.assoc j metasenv in
634 let jty = NCicUntrusted.apply_subst status subst ctx jty in
635 debug_print(lazy("goal " ^ (status#ppterm ctx [] [] jty)));
636 let res = fast_eq_check unit_eq status j in
637 debug_print(lazy("ritorno da fast_eq_check"));
640 | NCicEnvironment.ObjectNotFound s as e ->
641 raise (Error (lazy "eq_coerc non yet defined",Some e))
642 | Error _ as e -> debug_print (lazy "error"); raise e
643 (* FG: for now we catch TypeCheckerFailure; to be understood *)
644 | NCicTypeChecker.TypeCheckerFailure _ ->
645 debug_print (lazy "TypeCheckerFailure");
646 raise (Error (lazy "no proof found",None))
649 let compare_statuses ~past ~present =
650 let _,_,past,_,_ = past#obj in
651 let _,_,present,_,_ = present#obj in
652 List.map fst (List.filter (fun (i,_) -> not(List.mem_assoc i past)) present),
653 List.map fst (List.filter (fun (i,_) -> not (List.mem_assoc i present)) past)
656 (* paramodulation has only an implicit knoweledge of the symmetry of equality;
657 hence it is in trouble in proving (a = b) = (b = a) *)
658 let try_sym tac status g =
659 let sym_eq = Ast.Appl [Ast.Ident("sym_eq",None); Ast.Implicit `Vector] in
660 let _,_,metasenv,subst,_ = status#obj in
661 let _, context, gty = List.assoc g metasenv in
663 NCicParamod.is_equation status metasenv subst context gty
668 let new_status = instantiate_with_ast status g ("",0,sym_eq) in
669 let go, _ = compare_statuses ~past:status ~present:new_status in
670 assert (List.length go = 1);
671 let ng = List.hd go in
676 let smart_apply_tac t s =
677 let unit_eq = index_local_equations s#eq_cache s in
678 NTactics.distribute_tac (try_sym (smart_apply t unit_eq)) s
679 (* NTactics.distribute_tac (smart_apply t unit_eq) s *)
681 let smart_apply_auto t eq_cache =
682 NTactics.distribute_tac (try_sym (smart_apply t eq_cache))
683 (* NTactics.distribute_tac (smart_apply t eq_cache) *)
686 (****************** types **************)
689 type th_cache = (NCic.context * InvRelDiscriminationTree.t) list
691 (* cartesian: term set list -> term list set *)
694 [] -> NDiscriminationTree.TermListSet.empty
696 NDiscriminationTree.TermSet.fold
697 (fun x acc -> NDiscriminationTree.TermListSet.add [x] acc) l NDiscriminationTree.TermListSet.empty
699 let rest = cartesian tl in
700 NDiscriminationTree.TermSet.fold
702 NDiscriminationTree.TermListSet.fold (fun l acc' -> NDiscriminationTree.TermListSet.add (x::l) acc') rest acc
703 ) he NDiscriminationTree.TermListSet.empty
706 (* all_keys_of_cic_type: term -> term set *)
707 let all_keys_of_cic_type status metasenv subst context ty =
709 (* Here we are dropping the metasenv, but this should not raise any
710 exception (hopefully...) *)
712 NCicMetaSubst.saturate status ~delta:max_int metasenv subst context ty 0
718 NCic.Appl (he::tl) ->
721 let wty = NCicReduction.whd status ~delta:0 ~subst context ty in
723 NDiscriminationTree.TermSet.add ty (aux ty)
725 NDiscriminationTree.TermSet.union
726 (NDiscriminationTree.TermSet.add ty (aux ty))
727 (NDiscriminationTree.TermSet.add wty (aux wty))
730 NDiscriminationTree.TermListSet.fold
731 (fun l acc -> NDiscriminationTree.TermSet.add (NCic.Appl l) acc)
732 (cartesian ((NDiscriminationTree.TermSet.singleton he)::tl'))
733 NDiscriminationTree.TermSet.empty
734 | _ -> NDiscriminationTree.TermSet.empty
736 let ty,ity = saturate ty in
737 let wty,iwty = saturate (NCicReduction.whd status ~delta:0 ~subst context ty) in
739 [ity, NDiscriminationTree.TermSet.add ty (aux ty)]
741 [ity, NDiscriminationTree.TermSet.add ty (aux ty) ;
742 iwty, NDiscriminationTree.TermSet.add wty (aux wty) ]
745 let all_keys_of_type status t =
746 let _,_,metasenv,subst,_ = status#obj in
747 let context = ctx_of t in
748 let status, t = apply_subst status context t in
750 all_keys_of_cic_type status metasenv subst context
751 (snd (term_of_cic_term status t context))
755 (fun (intros,keys) ->
757 NDiscriminationTree.TermSet.fold
758 (fun t acc -> Ncic_termSet.add (mk_cic_term context t) acc)
759 keys Ncic_termSet.empty
764 let keys_of_type status orig_ty =
765 (* Here we are dropping the metasenv (in the status), but this should not
766 raise any exception (hopefully...) *)
767 let _, ty, _ = saturate ~delta:max_int status orig_ty in
768 let _, ty = apply_subst status (ctx_of ty) ty in
771 let orig_ty' = NCicTacReduction.normalize ~subst context orig_ty in
772 if orig_ty' <> orig_ty then
773 let ty',_,_= NCicMetaSubst.saturate ~delta:0 metasenv subst context orig_ty' 0 in
779 (*CSC: strange: we keep ty, ty normalized and ty ~delta:(h-1) *)
781 let _, ty = term_of_cic_term status ty (ctx_of ty) in
783 | NCic.Const (NReference.Ref (_,(NReference.Def h | NReference.Fix (_,_,h))))
784 | NCic.Appl (NCic.Const(NReference.Ref(_,(NReference.Def h | NReference.Fix (_,_,h))))::_)
786 let _,ty,_= saturate status ~delta:(h-1) orig_ty in
793 let all_keys_of_term status t =
794 let status, orig_ty = typeof status (ctx_of t) t in
795 all_keys_of_type status orig_ty
798 let keys_of_term status t =
799 let status, orig_ty = typeof status (ctx_of t) t in
800 keys_of_type status orig_ty
803 let mk_th_cache status gl =
805 (fun (status, acc) g ->
806 let gty = get_goalty status g in
807 let ctx = ctx_of gty in
808 noprint(lazy("th cache for: "^ppterm status gty));
809 noprint(lazy("th cache in: "^ppcontext status ctx));
810 if List.mem_assq ctx acc then status, acc else
811 let idx = InvRelDiscriminationTree.empty in
814 (fun (status, i, idx) _ ->
815 let t = mk_cic_term ctx (NCic.Rel i) in
816 let status, keys = keys_of_term status t in
817 noprint(lazy("indexing: "^ppterm status t ^ ": " ^ string_of_int (List.length keys)));
819 List.fold_left (fun idx k ->
820 InvRelDiscriminationTree.index idx k t) idx keys
825 status, (ctx, idx) :: acc)
829 let all_elements ctx cache =
830 let dummy = mk_cic_term ctx (NCic.Meta (0,(0, (NCic.Irl 0)))) in
832 let idx = List.assq ctx cache in
833 Ncic_termSet.elements
834 (InvRelDiscriminationTree.retrieve_unifiables idx dummy)
837 let add_to_th t c ty =
838 let key_c = ctx_of t in
839 if not (List.mem_assq key_c c) then
840 (key_c ,InvRelDiscriminationTree.index
841 InvRelDiscriminationTree.empty ty t ) :: c
843 let rec replace = function
845 | (x, idx) :: tl when x == key_c ->
846 (x, InvRelDiscriminationTree.index idx ty t) :: tl
847 | x :: tl -> x :: replace tl
852 let rm_from_th t c ty =
853 let key_c = ctx_of t in
854 if not (List.mem_assq key_c c) then assert false
856 let rec replace = function
858 | (x, idx) :: tl when x == key_c ->
859 (x, InvRelDiscriminationTree.remove_index idx ty t) :: tl
860 | x :: tl -> x :: replace tl
865 let pp_idx status idx =
866 InvRelDiscriminationTree.iter idx
868 noprint(lazy("K: " ^ NCicInverseRelIndexable.string_of_path k));
870 (fun t -> debug_print(lazy("\t"^ppterm status t)))
874 let pp_th (status: #NTacStatus.pstatus) =
877 noprint(lazy( "-----------------------------------------------"));
878 noprint(lazy( (status#ppcontext ~metasenv:[] ~subst:[] ctx)));
879 noprint(lazy( "||====> "));
883 let search_in_th gty th =
884 let c = ctx_of gty in
885 let rec aux acc = function
886 | [] -> (* Ncic_termSet.elements *) acc
889 let idx = List.assoc(*q*) k th in
890 let acc = Ncic_termSet.union acc
891 (InvRelDiscriminationTree.retrieve_unifiables idx gty)
894 with Not_found -> aux acc tl
896 aux Ncic_termSet.empty c
900 do_types : bool; (* solve goals in Type *)
901 last : bool; (* last goal: take first solution only *)
902 candidates: Ast.term list option;
903 local_candidates: bool;
910 {facts : th_cache; (* positive results *)
911 under_inspection : cic_term list * th_cache; (* to prune looping *)
912 failures : th_cache; (* to avoid repetitions *)
913 unit_eq : NCicParamod.state;
917 let add_to_trace status ~depth cache t =
920 debug_print ~depth (lazy ("Adding to trace: " ^ NotationPp.pp_term status t));
921 {cache with trace = t::cache.trace}
922 | Ast.NCic _ (* local candidate *)
923 | _ -> (*not an application *) cache
925 let pptrace status tr =
926 (lazy ("Proof Trace: " ^ (String.concat ";"
927 (List.map (NotationPp.pp_term status) tr))))
929 let remove_from_trace cache t =
932 (match cache.trace with
933 | _::tl -> {cache with trace = tl}
935 | Ast.NCic _ (* local candidate *)
936 | _ -> (*not an application *) cache *)
939 type goal = int * sort (* goal, depth, sort *)
940 type fail = goal * cic_term
941 type candidate = int * Ast.term (* unique candidate number, candidate *)
943 exception Gaveup of th_cache (* failure cache *)
944 exception Proved of NTacStatus.tac_status * Ast.term list
946 (* let close_failures _ c = c;; *)
947 (* let prunable _ _ _ = false;; *)
948 (* let cache_examine cache gty = `Notfound;; *)
949 (* let put_in_subst s _ _ _ = s;; *)
950 (* let add_to_cache_and_del_from_orlist_if_green_cut _ _ c _ _ o f _ = c, o, f, false ;; *)
951 (* let cache_add_underinspection c _ _ = c;; *)
953 let init_cache ?(facts=[]) ?(under_inspection=[],[])
955 ?(unit_eq=NCicParamod.empty_state)
960 under_inspection = under_inspection;
964 let only signature _context candidate = true
966 (* TASSI: nel trie ci mettiamo solo il body, non il ty *)
968 NCicTypeChecker.typeof ~subst:[] ~metasenv:[] [] candidate
970 let height = fast_height_of_term status candidate_ty in
971 let rc = signature >= height in
973 noprint (lazy ("Filtro: " ^ status#ppterm ~context:[] ~subst:[]
974 ~metasenv:[] candidate ^ ": " ^ string_of_int height))
976 noprint (lazy ("Tengo: " ^ status#ppterm ~context:[] ~subst:[]
977 ~metasenv:[] candidate ^ ": " ^ string_of_int height));
982 let candidate_no = ref 0;;
984 let openg_no status = List.length (head_goals status#stack)
986 let sort_candidates status ctx candidates =
987 let _,_,metasenv,subst,_ = status#obj in
989 let status,ct = disambiguate status ctx ("",0,cand) `XTNone in
990 let status,t = term_of_cic_term status ct ctx in
991 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
992 let res = branch status (mk_cic_term ctx ty) in
993 noprint (lazy ("branch factor for: " ^ (ppterm status ct) ^ " = "
994 ^ (string_of_int res)));
997 let candidates = List.map (fun t -> branch t,t) candidates in
999 List.sort (fun (a,_) (b,_) -> a - b) candidates in
1000 let candidates = List.map snd candidates in
1001 noprint (lazy ("candidates =\n" ^ (String.concat "\n"
1002 (List.map (NotationPp.pp_term status) candidates))));
1005 let sort_new_elems l =
1006 List.sort (fun (_,s1) (_,s2) -> openg_no s1 - openg_no s2) l
1008 let rec stack_goals level gs =
1009 if level = 0 then []
1011 | [] -> assert false
1013 let is_open = function
1014 | (_,Continuationals.Stack.Open i) -> Some i
1015 | (_,Continuationals.Stack.Closed _) -> None
1017 HExtlib.filter_map is_open g @ stack_goals (level-1) s
1020 let open_goals level status = stack_goals level status#stack
1023 let try_candidate ?(smart=0) flags depth status eq_cache ctx t =
1025 let old_og_no = List.length (open_goals (depth+1) status) in
1026 debug_print ~depth (lazy ("try " ^ (string_of_int smart) ^ " : "
1027 ^ (NotationPp.pp_term status) t));
1029 if smart = 0 then NTactics.apply_tac ("",0,t) status
1030 else if smart = 1 then
1031 smart_apply_auto ("",0,t) eq_cache status
1032 else (* smart = 2: both *)
1033 try NTactics.apply_tac ("",0,t) status
1035 smart_apply_auto ("",0,t) eq_cache status
1037 (* FG: this optimization rules out some applications of
1038 * lift_bind (from contribs/lambda_delta/Basic_2/substitution/lift.ma)
1040 (* we compare the expected branching with the actual one and
1041 prune the candidate when the latter is larger. The optimization
1042 is meant to rule out stange applications of flexible terms,
1043 such as the application of eq_f that always succeeds.
1044 There is some gain but less than expected *)
1045 let og_no = List.length (open_goals (depth+1) status) in
1046 let status, cict = disambiguate status ctx ("",0,t) None in
1047 let status,ct = term_of_cic_term status cict ctx in
1048 let _,_,metasenv,subst,_ = status#obj in
1049 let ty = NCicTypeChecker.typeof status subst metasenv ctx ct in
1050 let res = branch status (mk_cic_term ctx ty) in
1051 let diff = og_no - old_og_no in
1052 debug_print (lazy ("expected branching: " ^ (string_of_int res)));
1053 debug_print (lazy ("actual: branching" ^ (string_of_int diff)));
1054 (* some flexibility *)
1055 if og_no - old_og_no > res then
1056 (debug_print (lazy ("branch factor for: " ^ (ppterm status cict) ^ " = "
1057 ^ (string_of_int res) ^ " vs. " ^ (string_of_int og_no)));
1058 debug_print ~depth (lazy "strange application"); None)
1060 *) (incr candidate_no; Some ((!candidate_no,t),status))
1061 with Error (msg,exn) -> debug_print ~depth (lazy "failed"); None
1064 let sort_of status subst metasenv ctx t =
1065 let ty = NCicTypeChecker.typeof status subst metasenv ctx t in
1066 let metasenv',ty = NCicUnification.fix_sorts status metasenv subst ty in
1067 assert (metasenv = metasenv');
1068 NCicTypeChecker.typeof status subst metasenv ctx ty
1071 let type0= NUri.uri_of_string ("cic:/matita/pts/Type0.univ")
1074 let perforate_small status subst metasenv context t =
1075 let rec aux = function
1076 | NCic.Appl (hd::tl) ->
1078 let s = sort_of status subst metasenv context t in
1080 | NCic.Sort(NCic.Type [`Type,u])
1081 when u=type0 -> NCic.Meta (0,(0,NCic.Irl 0))
1084 NCic.Appl (hd::List.map map tl)
1090 let get_cands retrieve_for diff empty gty weak_gty =
1091 let cands = retrieve_for gty in
1093 | None -> cands, empty
1095 let more_cands = retrieve_for weak_gty in
1096 cands, diff more_cands cands
1099 let get_candidates ?(smart=true) ~pfailed depth flags status cache signature gty =
1100 let universe = status#auto_cache in
1101 let _,_,metasenv,subst,_ = status#obj in
1102 let context = ctx_of gty in
1103 let _, raw_gty = term_of_cic_term status gty context in
1104 let is_prod, is_eq =
1105 let status, t = term_of_cic_term status gty context in
1106 let t = NCicReduction.whd status subst context t in
1108 | NCic.Prod _ -> true, false
1109 | _ -> false, NCicParamod.is_equation status metasenv subst context t
1111 debug_print ~depth (lazy ("gty:" ^ NTacStatus.ppterm status gty));
1113 NCicParamod.is_equation status metasenv subst context raw_gty
1115 let raw_weak_gty, weak_gty =
1122 perforate_small status subst metasenv context raw_gty in
1123 let weak = mk_cic_term context raw_weak in
1124 noprint ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1125 Some raw_weak, Some (weak)
1129 (* we now compute global candidates *)
1130 let global_cands, smart_global_cands =
1131 if flags.local_candidates then
1133 let to_ast = function
1134 | NCic.Const r when true
1135 (*is_relevant statistics r*) -> Some (Ast.NRef r)
1136 (* | NCic.Const _ -> None *)
1137 | _ -> assert false in
1139 to_ast (NDiscriminationTree.TermSet.elements s) in
1142 (NDiscriminationTree.DiscriminationTree.retrieve_unifiables universe)
1143 NDiscriminationTree.TermSet.diff
1144 NDiscriminationTree.TermSet.empty
1145 raw_gty raw_weak_gty in
1148 (* we now compute local candidates *)
1149 let local_cands,smart_local_cands =
1150 if flags.local_candidates then
1153 let _status, t = term_of_cic_term status t context
1155 List.map to_ast (Ncic_termSet.elements s) in
1158 (fun ty -> search_in_th ty cache)
1159 Ncic_termSet.diff Ncic_termSet.empty gty weak_gty in
1162 (* we now splits candidates in facts or not facts *)
1163 let test = is_a_fact_ast status subst metasenv context in
1164 let by,given_candidates =
1165 match flags.candidates with
1167 | None -> false, [] in
1168 (* we compute candidates to be applied in normal mode, splitted in
1169 facts and not facts *)
1170 let candidates_facts,candidates_other =
1171 let gl1,gl2 = List.partition test global_cands in
1172 let ll1,ll2 = List.partition test local_cands in
1173 (* if the goal is an equation and paramodulation did not fail
1174 we avoid to apply unit equalities; refl is an
1175 exception since it prompts for convertibility *)
1176 let l1 = if is_eq && (not pfailed)
1177 then [Ast.Ident("refl",None)] else gl1@ll1 in
1179 (* if smart given candidates are applied in smart mode *)
1180 if by && smart then ll2
1181 else if by then given_candidates@ll2
1185 (* we now compute candidates to be applied in smart mode, splitted in
1186 facts and not facts *)
1187 let smart_candidates_facts, smart_candidates_other =
1188 if is_prod || not(smart) then [],[]
1190 let sgl1,sgl2 = List.partition test smart_global_cands in
1191 let sll1,sll2 = List.partition test smart_local_cands in
1192 let l1 = if is_eq then [] else sgl1@sll1 in
1194 if by && smart then given_candidates@sll2
1195 else if by then sll2
1200 smart_candidates_facts,
1201 sort_candidates status context (candidates_other),
1202 sort_candidates status context (smart_candidates_other)
1205 let applicative_case ~pfailed depth signature status flags gty cache =
1206 app_counter:= !app_counter+1;
1207 let _,_,metasenv,subst,_ = status#obj in
1208 let context = ctx_of gty in
1209 let tcache = cache.facts in
1210 let is_prod, is_eq =
1211 let status, t = term_of_cic_term status gty context in
1212 let t = NCicReduction.whd status subst context t in
1214 | NCic.Prod _ -> true, false
1215 | _ -> false, NCicParamod.is_equation status metasenv subst context t
1217 debug_print ~depth (lazy (string_of_bool is_eq));
1219 let candidates_facts, smart_candidates_facts,
1220 candidates_other, smart_candidates_other =
1221 get_candidates ~smart:true ~pfailed depth
1222 flags status tcache signature gty
1224 let sm = if is_eq || is_prod then 0 else 2 in
1225 let sm1 = if flags.last then 2 else 0 in
1226 let maxd = (depth + 1 = flags.maxdepth) in
1227 let try_candidates only_one sm acc candidates =
1230 if (only_one && (elems <> [])) then elems
1232 match try_candidate (~smart:sm)
1233 flags depth status cache.unit_eq context cand with
1235 | Some x -> x::elems)
1238 (* if the goal is the last one we stop at the first fact *)
1239 let elems = try_candidates flags.last sm [] candidates_facts in
1240 (* now we add smart_facts *)
1241 let elems = try_candidates flags.last sm elems smart_candidates_facts in
1242 (* if we are at maxdepth and the goal is not a product we are done
1243 similarly, if the goal is the last one and we already found a
1245 if (maxd && not(is_prod)) || (flags.last && elems<>[]) then elems
1247 let elems = try_candidates false 2 elems candidates_other in
1248 debug_print ~depth (lazy ("not facts: try smart application"));
1249 try_candidates false 2 elems smart_candidates_other
1255 (* gty is supposed to be meta-closed *)
1256 let is_subsumed depth filter_depth status gty cache =
1257 if cache=[] then false else (
1258 debug_print ~depth (lazy("Subsuming " ^ (ppterm status gty)));
1259 let n,h,metasenv,subst,obj = status#obj in
1260 let ctx = ctx_of gty in
1261 let _ , raw_gty = term_of_cic_term status gty ctx in
1262 let target = NCicSubstitution.lift status 1 raw_gty in
1263 (* we compute candidates using the perforated type *)
1270 perforate_small status subst metasenv ctx raw_gty in
1271 let weak = mk_cic_term ctx raw_weak in
1272 debug_print ~depth (lazy ("weak_gty:" ^ NTacStatus.ppterm status weak));
1276 (* candidates must only be searched w.r.t the given context *)
1279 let idx = List.assq ctx cache in
1282 Ncic_termSet.elements
1283 (InvRelDiscriminationTree.retrieve_unifiables idx weak)
1285 with Not_found -> []
1287 (* this is a dirty trick: the first argument of an application is used
1288 to remember at which depth a goal failed *)
1290 let ctx = ctx_of t in
1291 let _, src = term_of_cic_term status t ctx in
1293 | NCic.Appl [NCic.Implicit (`Typeof d); t]
1294 when d <= depth -> Some (mk_cic_term ctx t)
1297 if filter_depth then HExtlib.filter_map filter candidates else candidates in
1299 (lazy ("failure candidates: " ^ string_of_int (List.length candidates)));
1303 let _ , source = term_of_cic_term status t ctx in
1305 NCic.Prod("foo",source,target) in
1306 let metasenv,j,_,_ =
1307 NCicMetaSubst.mk_meta
1308 metasenv ctx ~with_type:implication `IsType in
1309 let status = status#set_obj (n,h,metasenv,subst,obj) in
1310 let status = status#set_stack [([1,Open j],[],[],`NoTag)] in
1312 let status = NTactics.intro_tac "foo" status in
1314 NTactics.apply_tac ("",0,Ast.NCic (NCic.Rel 1)) status
1316 if (head_goals status#stack = []) then raise Found
1321 with Found -> debug_print ~depth (lazy "success");true)
1324 let rec guess_name name ctx =
1325 if name = "_" then guess_name "auto" ctx else
1326 if not (List.mem_assoc name ctx) then name else
1327 guess_name (name^"'") ctx
1330 let is_prod status =
1331 let _, ctx, gty = current_goal status in
1332 let status, gty = apply_subst status ctx gty in
1333 let _, raw_gty = term_of_cic_term status gty ctx in
1335 | NCic.Prod (name,src,_) ->
1336 let status, src = whd status ~delta:0 ctx (mk_cic_term ctx src) in
1337 (match snd (term_of_cic_term status src ctx) with
1338 | NCic.Const(NReference.Ref (_,NReference.Ind _) as r)
1339 | NCic.Appl (NCic.Const(NReference.Ref (_,NReference.Ind _) as r)::_) ->
1340 let _,_,itys,_,_ = NCicEnvironment.get_checked_indtys status r in
1342 (* | [_,_,_,[_;_]] con nat va, ovviamente, in loop *)
1344 | [_,_,_,[]] -> `Inductive (guess_name name ctx)
1345 | _ -> `Some (guess_name name ctx))
1346 | _ -> `Some (guess_name name ctx))
1349 let intro ~depth status facts name =
1350 let status = NTactics.intro_tac name status in
1351 let _, ctx, ngty = current_goal status in
1352 let t = mk_cic_term ctx (NCic.Rel 1) in
1353 let status, keys = keys_of_term status t in
1354 let facts = List.fold_left (add_to_th t) facts keys in
1355 debug_print ~depth (lazy ("intro: "^ name));
1356 (* unprovability is not stable w.r.t introduction *)
1360 let rec intros_facts ~depth status facts =
1361 if List.length (head_goals status#stack) <> 1 then status, facts else
1362 match is_prod status with
1366 intro ~depth status facts name
1367 in intros_facts ~depth status facts
1368 (* | `Inductive name ->
1369 let status = NTactics.case1_tac name status in
1370 intros_facts ~depth status facts *)
1371 | _ -> status, facts
1374 let intros ~depth status ?(use_given_only=false) cache =
1375 match is_prod status with
1378 let trace = cache.trace in
1380 intros_facts ~depth status cache.facts
1382 if head_goals status#stack = [] then
1383 let status = NTactics.merge_tac status in
1384 [(0,Ast.Ident("__intros",None)),status], cache
1386 (* we reindex the equation from scratch *)
1387 let unit_eq = index_local_equations status#eq_cache status ~flag:use_given_only in
1388 let status = NTactics.merge_tac status in
1389 [(0,Ast.Ident("__intros",None)),status],
1390 init_cache ~facts ~unit_eq () ~trace
1394 let reduce ~whd ~depth status g =
1395 let n,h,metasenv,subst,o = status#obj in
1396 let attr, ctx, ty = NCicUtils.lookup_meta g metasenv in
1397 let ty = NCicUntrusted.apply_subst status subst ctx ty in
1399 (if whd then NCicReduction.whd else NCicTacReduction.normalize) status ~subst ctx ty
1404 (lazy ("reduced to: "^ status#ppterm ctx subst metasenv ty'));
1406 (g,(attr,ctx,ty'))::(List.filter (fun (i,_) -> i<>g) metasenv)
1408 let status = status#set_obj (n,h,metasenv,subst,o) in
1409 (* we merge to gain a depth level; the previous goal level should
1411 let status = NTactics.merge_tac status in
1413 [(!candidate_no,Ast.Ident("__whd",None)),status])
1416 let is_meta status gty =
1417 let _, ty = term_of_cic_term status gty (ctx_of gty) in
1419 | NCic.Meta _ -> true
1423 let do_something signature flags status g depth gty ?(use_given_only=false) cache =
1424 (* if the goal is meta we close it with I:True. This should work
1425 thanks to the toplogical sorting of goals. *)
1426 if is_meta status gty then
1427 let t = Ast.Ident("I",None) in
1428 debug_print (lazy ("using default term" ^ (NotationPp.pp_term status) t));
1429 let s = NTactics.apply_tac ("",0,t) status in
1432 let l0, cache = intros ~depth status cache ~use_given_only in
1433 if l0 <> [] then l0, cache
1436 let l = reduce ~whd:true ~depth status g in
1437 (* if l <> [] then l,cache else *)
1438 (* backward aplications *)
1443 ((!candidate_no,Ast.Ident("__paramod",None)),s))
1444 (auto_eq_check cache.unit_eq status)
1447 if ((l1 <> []) && flags.last) then [] else
1448 applicative_case ~pfailed:(l1=[]) depth signature status flags gty cache
1452 (fun ((_,t),_) -> toref incr_nominations statistics t) l2;
1453 (* states in l1 have have an empty set of subgoals: no point to sort them *)
1455 (lazy ("alternatives = " ^ (string_of_int (List.length (l1@l@l2)))));
1456 (* we order alternatives w.r.t the number of subgoals they open *)
1457 l1 @ (sort_new_elems l2) @ l, cache
1460 let pp_goal = function
1461 | (_,Continuationals.Stack.Open i)
1462 | (_,Continuationals.Stack.Closed i) -> string_of_int i
1465 let pp_goals status l =
1469 let gty = get_goalty status i in
1470 NTacStatus.ppterm status gty)
1477 let compare = Pervasives.compare
1481 module MS = HTopoSort.Make(M)
1484 let sort_tac status =
1486 match status#stack with
1487 | [] -> assert false
1488 | (goals, t, k, tag) :: s ->
1489 let g = head_goals status#stack in
1491 (List.rev (MS.topological_sort g (deps status))) in
1492 noprint (lazy ("old g = " ^
1493 String.concat "," (List.map string_of_int g)));
1494 noprint (lazy ("sorted goals = " ^
1495 String.concat "," (List.map string_of_int sortedg)));
1496 let is_it i = function
1497 | (_,Continuationals.Stack.Open j )
1498 | (_,Continuationals.Stack.Closed j ) -> i = j
1501 List.map (fun i -> List.find (is_it i) goals) sortedg
1503 (sorted_goals, t, k, tag) :: s
1505 status#set_stack gstatus
1508 let clean_up_tac status =
1510 match status#stack with
1511 | [] -> assert false
1512 | (g, t, k, tag) :: s ->
1513 let is_open = function
1514 | (_,Continuationals.Stack.Open _) -> true
1515 | (_,Continuationals.Stack.Closed _) -> false
1517 let g' = List.filter is_open g in
1518 (g', t, k, tag) :: s
1520 status#set_stack gstatus
1523 let focus_tac focus status =
1525 match status#stack with
1526 | [] -> assert false
1527 | (g, t, k, tag) :: s ->
1528 let in_focus = function
1529 | (_,Continuationals.Stack.Open i)
1530 | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1532 let focus,others = List.partition in_focus g
1534 (* we need to mark it as a BranchTag, otherwise cannot merge later *)
1535 (focus,[],[],`BranchTag) :: (others, t, k, tag) :: s
1537 status#set_stack gstatus
1540 let deep_focus_tac level focus status =
1541 let in_focus = function
1542 | (_,Continuationals.Stack.Open i)
1543 | (_,Continuationals.Stack.Closed i) -> List.mem i focus
1545 let rec slice level gs =
1546 if level = 0 then [],[],gs else
1548 | [] -> assert false
1549 | (g, t, k, tag) :: s ->
1550 let f,o,gs = slice (level-1) s in
1551 let f1,o1 = List.partition in_focus g
1553 (f1,[],[],`BranchTag)::f, (o1, t, k, tag)::o, gs
1556 let f,o,s = slice level status#stack in f@o@s
1558 status#set_stack gstatus
1561 let move_to_side level status =
1562 match status#stack with
1563 | [] -> assert false
1565 let is_open = function
1566 | (_,Continuationals.Stack.Open i) -> Some i
1567 | (_,Continuationals.Stack.Closed _) -> None
1569 let others = menv_closure status (stack_goals (level-1) tl) in
1570 List.for_all (fun i -> IntSet.mem i others)
1571 (HExtlib.filter_map is_open g)
1573 let top_cache ~depth top status ?(use_given_only=false) cache =
1575 let unit_eq = index_local_equations status#eq_cache status ~flag:use_given_only in
1576 {cache with unit_eq = unit_eq}
1579 let rec auto_clusters ?(top=false) flags signature cache depth ?(use_given_only=false) status : unit =
1580 debug_print ~depth (lazy ("entering auto clusters at depth " ^
1581 (string_of_int depth)));
1582 debug_print ~depth (pptrace status cache.trace);
1583 (* ignore(Unix.select [] [] [] 0.01); *)
1584 let status = clean_up_tac status in
1585 let goals = head_goals status#stack in
1587 if depth = 0 then raise (Proved (status, cache.trace))
1589 let status = NTactics.merge_tac status in
1591 let l,tree = cache.under_inspection in
1593 | [] -> cache (* possible because of intros that cleans the cache *)
1594 | a::tl -> let tree = rm_from_th a tree a in
1595 {cache with under_inspection = tl,tree}
1597 auto_clusters flags signature cache (depth-1) status ~use_given_only
1598 else if List.length goals < 2 then
1599 let cache = top_cache ~depth top status cache ~use_given_only in
1600 auto_main flags signature cache depth status ~use_given_only
1602 let all_goals = open_goals (depth+1) status in
1603 debug_print ~depth (lazy ("goals = " ^
1604 String.concat "," (List.map string_of_int all_goals)));
1605 let classes = HExtlib.clusters (deps status) all_goals in
1606 (* if any of the classes exceed maxwidth we fail *)
1609 if List.length gl > flags.maxwidth then
1611 debug_print ~depth (lazy "FAIL GLOBAL WIDTH");
1612 HLog.warn (sprintf "global width (%u) exceeded: %u"
1613 flags.maxwidth (List.length gl));
1614 raise (Gaveup cache.failures)
1615 end else ()) classes;
1616 if List.length classes = 1 then
1618 {flags with last = (List.length all_goals = 1)} in
1619 (* no need to cluster *)
1620 let cache = top_cache ~depth top status cache ~use_given_only in
1621 auto_main flags signature cache depth status ~use_given_only
1623 let classes = if top then List.rev classes else classes in
1629 ("cluster:" ^ String.concat "," (List.map string_of_int l)))
1631 (* we now process each cluster *)
1632 let status,cache,b =
1634 (fun (status,cache,b) gl ->
1636 {flags with last = (List.length gl = 1)} in
1637 let lold = List.length status#stack in
1638 debug_print ~depth (lazy ("stack length = " ^
1639 (string_of_int lold)));
1640 let fstatus = deep_focus_tac (depth+1) gl status in
1641 let cache = top_cache ~depth top fstatus cache ~use_given_only in
1643 debug_print ~depth (lazy ("focusing on" ^
1644 String.concat "," (List.map string_of_int gl)));
1645 auto_main flags signature cache depth fstatus ~use_given_only; assert false
1647 | Proved(status,trace) ->
1648 let status = NTactics.merge_tac status in
1649 let cache = {cache with trace = trace} in
1650 let lnew = List.length status#stack in
1651 assert (lold = lnew);
1653 | Gaveup failures when top ->
1654 let cache = {cache with failures = failures} in
1657 (status,cache,false) classes
1659 let rec final_merge n s =
1660 if n = 0 then s else final_merge (n-1) (NTactics.merge_tac s)
1661 in let status = final_merge depth status
1662 in if b then raise (Proved(status,cache.trace)) else raise (Gaveup cache.failures)
1666 (* BRAND NEW VERSION *)
1667 auto_main flags signature cache depth status ?(use_given_only=false): unit=
1668 debug_print ~depth (lazy "entering auto main");
1669 debug_print ~depth (pptrace status cache.trace);
1670 debug_print ~depth (lazy ("stack length = " ^
1671 (string_of_int (List.length status#stack))));
1672 (* ignore(Unix.select [] [] [] 0.01); *)
1673 let status = sort_tac (clean_up_tac status) in
1674 let goals = head_goals status#stack in
1676 | [] when depth = 0 -> raise (Proved (status,cache.trace))
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 ~use_given_only
1688 if depth > 0 && move_to_side depth status
1690 let status = NTactics.merge_tac status in
1692 let l,tree = cache.under_inspection in
1694 | [] -> cache (* possible because of intros that cleans the cache*)
1695 | a::tl -> let tree = rm_from_th a tree a in
1696 {cache with under_inspection = tl,tree}
1698 auto_clusters flags signature cache (depth-1) status ~use_given_only
1700 let ng = List.length goals in
1701 (* moved inside auto_clusters *)
1702 if ng > flags.maxwidth then begin
1703 debug_print ~depth (lazy "FAIL LOCAL WIDTH");
1704 HLog.warn (sprintf "local width (%u) exceeded: %u"
1706 raise (Gaveup cache.failures)
1707 end else if depth = flags.maxdepth then
1708 raise (Gaveup cache.failures)
1710 let status = NTactics.branch_tac ~force:true status in
1711 let g,gctx, gty = current_goal status in
1712 let ctx,ty = close status g in
1713 let closegty = mk_cic_term ctx ty in
1714 let status, gty = apply_subst status gctx gty in
1715 debug_print ~depth (lazy("Attacking goal " ^
1716 string_of_int g ^ " : "^ppterm status gty));
1717 debug_print ~depth (lazy ("current failures: " ^
1718 string_of_int (List.length (all_elements ctx cache.failures))));
1720 let _,_,metasenv,subst,_ = status#obj in
1721 NCicParamod.is_equation status metasenv subst ctx ty in
1722 (* if the goal is an equality we artificially raise its depth up to
1723 flags.maxdepth - 1 *)
1724 if (not flags.last && is_eq && (depth < (flags.maxdepth -2))) then
1725 (* for efficiency reasons, in this case we severely cripple the
1727 (debug_print ~depth (lazy ("RAISING DEPTH TO " ^ string_of_int (depth+1)));
1728 auto_main flags signature cache (depth+1) status ~use_given_only)
1729 (* check for loops *)
1730 else if is_subsumed depth false status closegty (snd cache.under_inspection) then
1731 (debug_print ~depth (lazy "SUBSUMED");
1732 raise (Gaveup cache.failures))
1733 (* check for failures *)
1734 else if is_subsumed depth true status closegty cache.failures then
1735 (debug_print ~depth (lazy "ALREADY MET");
1736 raise (Gaveup cache.failures))
1738 let new_sig = height_of_goal g status in
1739 if new_sig < signature then
1740 (debug_print ~depth (lazy ("news = " ^ (string_of_int new_sig)));
1741 debug_print ~depth (lazy ("olds = " ^ (string_of_int signature))));
1742 let alternatives, cache =
1743 do_something signature flags status g depth gty cache ~use_given_only in
1746 let l,tree = cache.under_inspection in
1747 let l,tree = closegty::l, add_to_th closegty tree closegty in
1748 {cache with under_inspection = l,tree}
1752 (fun allfailures ((_,t),status) ->
1754 (lazy ("(re)considering goal " ^
1755 (string_of_int g) ^" : "^ppterm status gty));
1756 debug_print (~depth:depth)
1757 (lazy ("Case: " ^ NotationPp.pp_term status t));
1759 if t=Ast.Ident("__whd",None) ||
1760 t=Ast.Ident("__intros",None)
1762 else depth+1,loop_cache in
1763 let cache = add_to_trace status ~depth cache t in
1764 let cache = {cache with failures = allfailures} in
1766 auto_clusters flags signature cache depth status ~use_given_only;
1769 debug_print ~depth (lazy "Failed");
1771 cache.failures alternatives in
1775 let dty = NCic.Appl [NCic.Implicit (`Typeof depth); ty] in
1778 (*prerr_endline ("FAILURE : " ^ ppterm status gty);*)
1779 add_to_th newfail failures closegty
1781 debug_print ~depth (lazy "no more candidates");
1782 raise (Gaveup failures)
1785 let int name l def =
1786 try int_of_string (List.assoc name l)
1787 with Failure _ | Not_found -> def
1790 module AstSet = Set.Make(struct type t = Ast.term let compare = compare end)
1792 let cleanup_trace s trace =
1793 (* removing duplicates *)
1796 (fun acc t -> AstSet.add t acc)
1797 AstSet.empty trace in
1798 let trace = AstSet.elements trace_set
1799 (* filtering facts *)
1803 | Ast.NRef (NReference.Ref (u,_)) -> not (is_a_fact_obj s u)
1809 - auto_params e' una high tactic che prende in input i parametri e poi li
1810 processa nel contesto vuoto calcolando i candidate
1812 - astrarla su una auto_params' che prende in input gia' i candidate e un
1813 nuovo parametro per evitare il calcolo dei candidate locali che invece
1814 diventano vuoti (ovvero: non usare automaticamente tutte le ipotesi, bensi'
1817 - reimplementi la auto_params chiamando la auto_params' con il flag a
1818 false e il vecchio codice per andare da parametri a candiddati
1819 OVVERO: usa tutti le ipotesi locali + candidati globali
1821 - crei un nuovo entry point lowtac che calcola i candidati usando il contesto
1822 corrente e poi fa exec della auto_params' con i candidati e il flag a true
1823 OVVERO: usa solo candidati globali che comprendono ipotesi locali
1826 type auto_params = NTacStatus.tactic_term list option * (string * string) list
1828 (*let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =*)
1829 let auto_tac' candidates ~local_candidates ?(use_given_only=false) flags ?(trace_ref=ref []) status =
1830 let oldstatus = status in
1831 let status = (status:> NTacStatus.tac_status) in
1832 let goals = head_goals status#stack in
1833 let status, facts = mk_th_cache status goals in
1834 (* let unit_eq = index_local_equations status#eq_cache status in *)
1835 let cache = init_cache ~facts () in
1836 (* pp_th status facts; *)
1838 NDiscriminationTree.DiscriminationTree.iter status#auto_cache (fun p t ->
1840 NDiscriminationTree.NCicIndexable.string_of_path p ^ " |--> " ^
1841 String.concat "\n " (List.map (
1842 status#ppterm ~metasenv:[] ~context:[] ~subst:[])
1843 (NDiscriminationTree.TermSet.elements t))
1846 let depth = int "depth" flags 3 in
1847 let size = int "size" flags 10 in
1848 let width = int "width" flags 4 (* (3+List.length goals)*) in
1850 (* let goals = List.map (fun i -> (i,P)) goals in *)
1851 let signature = height_of_goals status in
1854 candidates = candidates;
1855 local_candidates = local_candidates;
1861 let initial_time = Unix.gettimeofday() in
1866 ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1868 ("Applicative nodes:"^string_of_int !app_counter));
1869 raise (Error (lazy "auto gave up", None)))
1871 let _ = debug_print (lazy("\n\nRound "^string_of_int x^"\n")) in
1872 let flags = { flags with maxdepth = x }
1874 try auto_clusters (~top:true) flags signature cache 0 status ~use_given_only;assert false
1876 try auto_main flags signature cache 0 status;assert false
1879 | Gaveup _ -> up_to (x+1) y
1880 | Proved (s,trace) ->
1881 debug_print (lazy ("proved at depth " ^ string_of_int x));
1882 List.iter (toref incr_uses statistics) trace;
1883 let trace = cleanup_trace s trace in
1884 let _ = debug_print (pptrace status trace) in
1887 | (g,t,k,f) :: rest -> (filter_open g,t,k,f):: rest
1890 let s = s#set_stack stack in
1892 oldstatus#set_status s
1894 let s = up_to depth depth in
1895 debug_print (print_stat status statistics);
1897 ("TIME ELAPSED:"^string_of_float(Unix.gettimeofday()-.initial_time)));
1899 ("Applicative nodes:"^string_of_int !app_counter));
1903 let candidates_from_ctx univ ctx status =
1908 (* FG: `XTSort here? *)
1909 let status, res = disambiguate status ctx t `XTNone in
1910 let _,res = term_of_cic_term status res (ctx_of res)
1912 in Some (List.map to_Ast l)
1914 let auto_lowtac ~params:(univ,flags) status goal =
1915 let gty = get_goalty status goal in
1916 let ctx = ctx_of gty in
1917 let candidates = candidates_from_ctx univ ctx status in
1918 auto_tac' candidates ~local_candidates:true ~use_given_only:false flags ~trace_ref:(ref [])
1920 let auto_tac ~params:(univ,flags) ?(trace_ref=ref []) status =
1921 let candidates = candidates_from_ctx univ [] status in
1922 auto_tac' candidates ~local_candidates:true ~use_given_only:false flags ~trace_ref status
1924 let auto_tac ~params:(_,flags as params) ?trace_ref =
1925 if List.mem_assoc "demod" flags then
1927 else if List.mem_assoc "paramod" flags then
1929 else if List.mem_assoc "fast_paramod" flags then
1930 fast_eq_check_tac ~params
1931 else auto_tac ~params ?trace_ref