]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/software/components/ng_tactics/nAuto.ml
Error message fixed (dereferencing must be done eagerly, not when the error is
[helm.git] / helm / software / components / ng_tactics / nAuto.ml
index bdcb98969d546a78703029b5e8f184f10f130079..4193d41da75b58035ca3c5c0565a645f8e9eae51 100644 (file)
@@ -13,7 +13,7 @@
 
 open Printf
 
-let debug = false
+let debug = true
 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
 
 open Continuationals.Stack
@@ -38,10 +38,10 @@ let auto_paramod ~params:(l,_) status goal =
   match
     NCicParamod.nparamod status metasenv subst (ctx_of gty) (NCic.Rel ~-1,t) l 
   with
-  | [] -> raise (NTacStatus.Error (lazy "no proof found",None))
+  | [] -> raise (Error (lazy "no proof found",None))
   | (pt, metasenv, subst)::_ -> 
       let status = status#set_obj (n,h,metasenv,subst,o) in
-      instantiate status goal (NTacStatus.mk_cic_term (ctx_of gty) pt)
+      instantiate status goal (mk_cic_term (ctx_of gty) pt)
 ;;
 
 let auto_paramod_tac ~params status = 
@@ -912,19 +912,72 @@ let auto_tac ~(dbd:HSql.dbd) ~params:(univ,params) ~automation_cache (proof, goa
 ;;
 *)
 
-module CacheElem : Set.OrderedType =
- struct
-  type t = 
-   | Failed_in of int * NCic.term     (* depth, goal type *)
-   | Succeded of Cic.term * Cic.term  (* proof, proof type *)
-   | UnderInspection of Cic.term      (* avoid looping *)
 
-  let compare = Pervasives.compare
- end
+type th_cache = (NCic.context * InvRelDiscriminationTree.t) list
 
-module CacheSet = Set.Make(CacheElem)
-module Cache = 
-  Discrimination_tree.Make(NDiscriminationTree.NCicIndexable)(CacheSet)
+let mk_th_cache status gl = 
+  List.fold_left 
+    (fun (status, acc) g ->
+       let gty = get_goalty status g in
+       let ctx = ctx_of gty in
+       if List.mem_assq ctx acc then status, acc else
+         let idx = InvRelDiscriminationTree.empty in
+         let status,_,idx = 
+           List.fold_left (fun (status, i, idx) _ -> 
+              let t = mk_cic_term ctx (NCic.Rel i) in
+              let status, ty = typeof status ctx t in
+              let _, ty, _ = saturate status ty in
+              let idx = InvRelDiscriminationTree.index idx ty t in
+              status, i+1, idx)
+             (status, 1, idx) ctx
+          in
+         status, (ctx, idx) :: acc)
+    (status,[]) gl
+;;
+
+let add_to_th t ty c = 
+  let key_c = ctx_of t in
+  if not (List.mem_assq key_c c) then
+      (key_c ,InvRelDiscriminationTree.index 
+               InvRelDiscriminationTree.empty ty t ) :: c 
+  else
+    let rec replace = function
+      | [] -> []
+      | (x, idx) :: tl when x == key_c -> 
+          (x, InvRelDiscriminationTree.index idx ty t) :: tl
+      | x :: tl -> x :: replace tl
+    in 
+      replace c
+;;
+
+let search_in_th gty th = 
+  let c = ctx_of gty in
+  let rec aux acc = function
+   | [] -> Ncic_termSet.elements acc
+   | (_::tl) as k ->
+       try 
+         let idx = List.assq k th in
+         let acc = Ncic_termSet.union acc 
+           (InvRelDiscriminationTree.retrieve_unifiables idx gty)
+         in
+         aux acc tl
+       with Not_found -> aux acc tl
+  in
+    aux Ncic_termSet.empty c
+;;
+
+let pp_th status = 
+  List.iter 
+    (fun ctx, idx ->
+       prerr_endline "-----------------------------------------------";
+       prerr_endline (NCicPp.ppcontext ~metasenv:[] ~subst:[] ctx);
+       prerr_endline "||====>  ";
+       InvRelDiscriminationTree.iter idx
+          (fun k set ->
+             prerr_endline ("K: " ^ NCicInverseRelIndexable.string_of_path k);
+             Ncic_termSet.iter 
+             (fun t -> prerr_endline ("\t"^ppterm status t)) set))
+;;
 
 type cache_examination_result =
   [ `Failed_in of int
@@ -934,31 +987,29 @@ type cache_examination_result =
   ]
 
 type sort = T | P
-type goal = int * int * sort
-type fail = goal * NCic.term
-type candidate = NCic.term
-type menv = NCic.metasenv
-type subst = NCic.substitution
+type goal = int * int * sort (* goal, depth, sort *)
+type fail = goal * cic_term
+type candidate = int * Ast.term (* unique candidate number, candidate *)
 
 type op = 
   (* goal has to be proved *)
   | D of goal 
   (* goal has to be cached as a success obtained using candidate as the first
    * step *)
-  | S of goal * Cache.input * candidate (* int was minsize *)
-type elem = 
+  | S of goal * cic_term * candidate (* int was minsize *)
+type 'a elem = 
   (* menv, subst, size, operations done (only S), operations to do, 
    * failures to cache if any op fails *)
-  menv * subst * int * op list * op list * fail list 
+  (#tac_status as 'a) * int * op list * op list * fail list 
 
-type auto_status = 
+type 'a auto_status = 
   (* list of computations that may lead to the solution: all op list will
    * end with the same (S(g,_)) *)
-  elem list * Cache.t
+  'a elem list * th_cache
 
-type auto_result = 
+type 'a auto_result = 
   | Gaveup 
-  | Proved of menv * subst * auto_status (* the alternative proofs *)
+  | Proved of (#tac_status as 'a) * 'a auto_status (* alt. proofs *)
 
 type flags = {
         do_types : bool; (* solve goals in Type *)
@@ -967,15 +1018,106 @@ type flags = {
         timeout  : float;
 }
 
-let close_failures = assert false;;
-let equational_and_applicative_case = assert false;;
-let prunable = assert false;;
-let cache_examine = assert false;;
-let put_in_subst = assert false;;
-let calculate_goal_ty = assert false;;
-let add_to_cache_and_del_from_orlist_if_green_cut = assert false;;
-let cache_add_underinspection = assert false;;
+let close_failures _ c = c;;
+let prunable _ _ _ = false;;
+let cache_examine cache gty = `Notfound;;
+let put_in_subst s _ _ _  = s;;
+let add_to_cache_and_del_from_orlist_if_green_cut _ _ c _ _ o f _ = c, o, f, false ;; 
+let cache_add_underinspection c _ _ = c;;
+let equational_case _ _ _ _ _ _ = [];;
+let sort_new_elems l = l;;
+let only _ _ _ = true;;
+
+let candidate_no = ref 0;;
+
+let try_candidate status t g =
+ try
+   debug_print (lazy (" try " ^ CicNotationPp.pp_term t));
+   let status = NTactics.focus_tac [g] status in
+   let status = NTactics.apply_tac ("",0,t) status in
+   let open_goals = head_goals status#stack in
+   debug_print 
+     (lazy (" success: "^String.concat " "(List.map string_of_int open_goals)));
+   incr candidate_no;
+   Some ((!candidate_no,t),status,open_goals)
+ with Error (msg,exn) -> debug_print (lazy " failed"); None
+;;
+
+let rec mk_irl n = function
+  | [] -> []
+  | _ :: tl -> NCic.Rel n :: mk_irl (n+1) tl
+;;
 
+let get_candidates status cache_th signature gty =
+  let universe = status#auto_cache in
+  let context = ctx_of gty in
+  let _, raw_gty = term_of_cic_term status gty context in
+  let cands = 
+    NDiscriminationTree.DiscriminationTree.retrieve_unifiables universe raw_gty
+  in
+  let cands = 
+    List.filter (only signature context) 
+      (NDiscriminationTree.TermSet.elements cands)
+  in
+  List.map (fun t -> 
+     let _status, t = term_of_cic_term status t context in Ast.NCic t) 
+     (search_in_th gty cache_th)
+  @ 
+  List.map (function NCic.Const r -> Ast.NRef r | _ -> assert false) cands
+;;
+
+let applicative_case signature status flags g gty cache = 
+  let candidates = get_candidates status cache signature gty in
+  debug_print (lazy ("candidates: " ^ string_of_int (List.length candidates)));
+  let elems = 
+    List.fold_left 
+      (fun elems cand ->
+        match try_candidate status cand g with
+        | None -> elems
+        | Some x -> x::elems)
+      [] candidates
+  in
+  elems
+;;
+
+let equational_and_applicative_case
+  signature flags status g depth gty cache 
+=
+ let elems = 
+  if false (*is_equational_case gty flags*) then
+    let elems =
+      equational_case
+        signature status flags g gty cache 
+    in
+    let more_elems =
+        applicative_case 
+          signature status flags g gty cache 
+    in
+      elems@more_elems
+  else
+    let elems =
+      (*match LibraryObjects.eq_URI () with
+      | Some _ ->
+         smart_applicative_case dbd tables depth s fake_proof goalno 
+           gty m context signature universe cache flags
+      | None -> *)
+         applicative_case 
+          signature status flags g gty cache 
+    in
+      elems
+ in
+ let elems = 
+    (* XXX calculate the sort *)
+   List.map (fun c,s,gl -> c,s,List.map (fun i -> i,depth-1,P) gl) elems 
+ in
+ let elems = sort_new_elems elems in
+ elems, cache
+;;
+
+let calculate_goal_ty (goalno,_,_) status = 
+  try Some (get_goalty status goalno)
+  with Error _ -> None
+;;
 let d_goals l =
   let rec aux acc = function
     | (D g)::tl -> aux (acc@[g]) tl
@@ -996,8 +1138,44 @@ let remove_s_from_fl (id,_,_) (fl : fail list) =
     aux fl
 ;;
 
-let auto_main status context flags signature elems cache =
-  let rec aux (elems, cache : auto_status) =
+let rec guess_name name ctx = 
+  if name = "_" then guess_name "auto" ctx else
+  if not (List.mem_assoc name ctx) then name else
+  guess_name (name^"'") ctx
+;;
+
+let intro_case status gno gty depth cache name =
+   let status = NTactics.focus_tac [gno] status in
+   let status = NTactics.intro_tac (guess_name name (ctx_of gty)) status in
+   let open_goals = head_goals status#stack in
+   assert (List.length open_goals  = 1);
+   let open_goal = List.hd open_goals in
+   let status, cache =
+     let ngty = get_goalty status open_goal in
+     let ctx = ctx_of ngty in
+     let t = mk_cic_term ctx (NCic.Rel 1) in
+     let status, ty = typeof status ctx t in
+     let _status, ty, _args = saturate status ty in
+     status, add_to_th t ty cache 
+   in
+   debug_print (lazy (" intro: "^ string_of_int open_goal));
+(*    pp_th status cache; *)
+   incr candidate_no;
+    (* XXX calculate the sort *)
+   [(!candidate_no,Ast.Implicit `JustOne),status,[open_goal,depth,P]],
+   cache
+;;
+                      
+let do_something signature flags s gno depth gty cache =
+  let _s, raw_gty = term_of_cic_term s gty (ctx_of gty) in
+  match raw_gty with
+  | NCic.Prod (name,_,_) -> intro_case s gno gty depth cache name
+  | _ -> 
+      equational_and_applicative_case signature flags s gno depth gty cache
+;;
+
+let auto_main flags signature elems cache =
+  let rec aux (elems, cache : 'a auto_status) =
 (* processa le hint dell'utente *)
 (*     let cache, elems = filter_prune_hint cache elems in *)
     match elems with
@@ -1012,47 +1190,44 @@ let auto_main status context flags signature elems cache =
           aux tables flags cache elems)
 *)
     | [] ->
-        (* complete failure *)
         debug_print (lazy "gave up");
         Gaveup
-    | (m, s, _, _, [],_)::orlist ->
-        (* complete success *)
+    | (s, _, _, [],_)::orlist ->
         debug_print (lazy "success");
-        Proved (m, s, (orlist, cache))
-    | (m, s, size, don, (D (_,_,T))::todo, fl)::orlist 
+        Proved (s, (orlist, cache))
+    | (s, size, don, (D (_,_,T))::todo, fl)::orlist 
       when not flags.do_types ->
-        (* skip since not Prop, don't even check if closed by side-effect *)
         debug_print (lazy "skip goal in Type");
-        aux ((m, s, size, don, todo, fl)::orlist, cache)
-    | (m, s, size, don, (S(g, key, c) as op)::todo, fl)::orlist ->
-        (* partial success, cache g and go on *)
+        aux ((s, size, don, todo, fl)::orlist, cache)
+    | (s, size, don, (S(g, key, c) as op)::todo, fl)::orlist ->
         let cache, orlist, fl, sibling_pruned = 
           add_to_cache_and_del_from_orlist_if_green_cut 
-            g s m cache key todo orlist fl context size 
+            g s cache key todo orlist fl size 
         in
         let fl = remove_s_from_fl g fl in
         let don = if sibling_pruned then don else op::don in
-        aux ((m, s, size, don, todo, fl)::orlist, cache)
-    | (m, s, size, don, todo, fl)::orlist 
+        let s = NTactics.unfocus_tac s in
+        aux ((s, size, don, todo, fl)::orlist, cache)
+    | (s, size, don, todo, fl)::orlist 
       when List.length(prop_only (d_goals todo)) > flags.maxwidth ->
         debug_print (lazy ("FAIL: WIDTH"));
         aux (orlist, cache)
-    | (m, s, size, don, todo, fl)::orlist when size > flags.maxsize ->
+    | (s, size, don, todo, fl)::orlist when size > flags.maxsize ->
         debug_print (lazy ("FAIL: SIZE: "^string_of_int size ^ 
             " > " ^ string_of_int flags.maxsize ));
         aux (orlist, cache)
     | _ when Unix.gettimeofday () > flags.timeout ->
         debug_print (lazy ("FAIL: TIMEOUT"));
         Gaveup 
-    | (m, s, size, don, (D (gno,depth,_ as g))::todo, fl)::orlist as status ->
+    | (s, size, don, (D (gno,depth,_ as g))::todo, fl)::orlist ->
         debug_print (lazy "attack goal");
-        match calculate_goal_ty g s with
+        match calculate_goal_ty g s with
         | None -> 
             debug_print (lazy ("SUCCESS: SIDE EFFECT: " ^ string_of_int gno));
-            aux ((m,s,size,don,todo, fl)::orlist, cache)
-        | Some (canonical_ctx, gty) ->
-            debug_print (lazy ("EXAMINE: "^
-              NCicPp.ppterm ~metasenv:m ~subst:s ~context gty));
+            aux ((s,size,don,todo, fl)::orlist, cache)
+        | Some gty ->
+            let s, gty = apply_subst s (ctx_of gty) gty in
+            debug_print (lazy ("EXAMINE: "^ ppterm s gty));
             match cache_examine cache gty with
             | `Failed_in d when d >= depth -> 
                 debug_print (lazy ("FAIL: DEPTH (cache): "^string_of_int gno));
@@ -1064,12 +1239,12 @@ let auto_main status context flags signature elems cache =
                 aux (orlist,cache)
             | `Succeded t -> 
                 debug_print (lazy ("SUCCESS: CACHE HIT: " ^ string_of_int gno));
-                let s, m = put_in_subst s m g canonical_ctx t gty in
-                aux ((m, s, size, don,todo, fl)::orlist, cache)
+                let s = put_in_subst s g t gty in
+                aux ((s, size, don,todo, fl)::orlist, cache)
             | `Notfound 
             | `Failed_in _ when depth > 0 -> 
                 ( (* more depth or is the first time we see the goal *)
-                    if prunable s gty todo then
+                    if prunable s gty todo then
                       (debug_print (lazy( "FAIL: LOOP: one father is equal"));
                        let cache = close_failures fl cache in
                        aux (orlist,cache))
@@ -1077,11 +1252,10 @@ let auto_main status context flags signature elems cache =
                     let cache = cache_add_underinspection cache gty depth in
                     debug_print (lazy ("INSPECTING: " ^ 
                         string_of_int gno ^ "("^ string_of_int size ^ "): "^
-                        NCicPp.ppterm ~metasenv:m ~subst:s ~context gty));
+                        ppterm s gty));
                     (* elems are possible computations for proving gty *)
-                    let elems =
-                      equational_and_applicative_case 
-                        signature status flags m s g gty cache context
+                    let elems, cache = 
+                      do_something signature flags s gno depth gty cache
                     in
                     if elems = [] then
                       (* this goal has failed *)
@@ -1095,19 +1269,19 @@ let auto_main status context flags signature elems cache =
                         let inj_gl gl = List.map (fun g -> D g) gl in
                         let rec map = function
                           | [] -> assert false
-                          | (cand,m,s,gl)::[] ->
+                          | (cand,s,gl)::[] ->
                               let todo = 
                                 inj_gl gl @ (S(g,gty,cand))::todo 
                               in
                               (* we are the last in OR, we fail on g and 
                                * also on all failures implied by g *)
-                              (m,s, size + size_gl gl, don, todo, (g,gty)::fl)
+                              (s, size + size_gl gl, don, todo, (g,gty)::fl)
                               :: orlist
-                          | (cand,m,s,gl)::tl -> 
+                          | (cand,s,gl)::tl -> 
                               let todo = 
                                 inj_gl gl @ (S(g,gty,cand))::todo 
                               in
-                              (m,s, size + size_gl gl, don, todo, []) :: map tl
+                              (s, size + size_gl gl, don, todo, []) :: map tl
                         in
                           map elems
                       in
@@ -1117,18 +1291,37 @@ let auto_main status context flags signature elems cache =
                 let cache = close_failures fl cache in
                 aux (orlist, cache)
   in
-    (aux (elems, cache) : auto_result)
+    (aux (elems, cache) : 'a auto_result)
 ;;
 
-let auto_tac ~params status =
-  prerr_endline "I teoremi noti sono";
-  NDiscriminationTree.DiscriminationTree.iter status#auto_cache
-    (fun _ t -> 
-      List.iter (fun t ->
-       prerr_endline
-        (NCicPp.ppterm ~metasenv:[] ~subst:[] ~context:[] t))
-       (NDiscriminationTree.TermSet.elements t));
-  status
+let int name l def = 
+  try int_of_string (List.assoc name l)
+  with Failure _ | Not_found -> def
+;;
+
+let auto_tac ~params:(_univ,flags) status =
+  let goals = head_goals status#stack in
+  let status, cache = mk_th_cache status goals in
+  let depth = int "depth" flags 3 in 
+  (* XXX fix sort *)
+  let goals = List.map (fun i -> D(i,depth,P)) goals in
+  let elems = [status,0,[],goals,[]] in
+  let signature = () in
+  let flags = { 
+          maxwidth = 3 + List.length goals; 
+          maxsize = 10; 
+          timeout = Unix.gettimeofday() +. 3000.;
+          do_types = false; 
+  } in
+  match auto_main flags signature elems cache with
+  | Gaveup -> raise (Error (lazy "auto gave up", None))
+  | Proved (s, (_orlist, _cache)) -> 
+      let stack = 
+        match s#stack with
+        | (g,t,k,f) :: rest -> (filter_open g,t,k,f):: rest
+        | _ -> assert false
+      in
+      s#set_stack stack
 ;;