]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/tactics/auto.ml
The singature of the "by" universe is added to the goal signature
[helm.git] / helm / software / components / tactics / auto.ml
1 (* Copyright (C) 2002, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26 open AutoTypes;;
27 open AutoCache;;
28
29 let debug = false;;
30 let debug_print s = 
31   if debug then prerr_endline (Lazy.force s);;
32
33
34 let mk_irl ctx = CicMkImplicit.identity_relocation_list_for_metavariable ctx;;
35 let ugraph = CicUniv.oblivion_ugraph;;
36 let typeof = CicTypeChecker.type_of_aux';;
37 let ppterm ctx t = 
38   let names = List.map (function None -> None | Some (x,_) -> Some x) ctx in
39   CicPp.pp t names
40 ;;
41 let is_propositional context sort = 
42   match CicReduction.whd context sort with
43   | Cic.Sort Cic.Prop 
44   | Cic.Sort (Cic.CProp _) -> true
45   | _-> false
46 ;;
47 let is_in_prop context subst metasenv ty =
48   let sort,u = typeof ~subst metasenv context ty CicUniv.oblivion_ugraph in
49   is_propositional context sort
50 ;;
51
52 exception NotConvertible;;
53
54 let check_proof_is_valid proof metasenv context goalty =
55   if debug then
56     begin
57       try
58         let ty,u = typeof metasenv context proof CicUniv.oblivion_ugraph in
59         let b,_ = CicReduction.are_convertible context ty goalty u in
60         if not b then raise NotConvertible else b
61       with _ ->
62         let names = 
63           List.map (function None -> None | Some (x,_) -> Some x) context 
64         in
65           debug_print (lazy ("PROOF:" ^ CicPp.pp proof names));
66           (* debug_print (lazy ("PROOFTY:" ^ CicPp.pp ty names)); *)
67           debug_print (lazy ("GOAL:" ^ CicPp.pp goalty names));
68           debug_print (lazy ("MENV:" ^ CicMetaSubst.ppmetasenv [] metasenv));
69         false
70     end
71   else true
72 ;;
73
74 let assert_proof_is_valid proof metasenv context goalty =
75   assert (check_proof_is_valid proof metasenv context goalty)
76 ;;
77
78 let assert_subst_are_disjoint subst subst' =
79   if debug then
80     assert(List.for_all
81              (fun (i,_) -> List.for_all (fun (j,_) -> i<>j) subst') 
82              subst)
83   else ()
84 ;;
85
86 let split_goals_in_prop metasenv subst gl =
87   List.partition 
88     (fun g ->
89       let _,context,ty = CicUtil.lookup_meta g metasenv in
90       try
91         let sort,u = typeof ~subst metasenv context ty ugraph in
92         is_propositional context sort
93       with 
94       | CicTypeChecker.AssertFailure s 
95       | CicTypeChecker.TypeCheckerFailure s -> 
96           debug_print 
97             (lazy ("NON TIPA" ^ ppterm context (CicMetaSubst.apply_subst subst ty)));
98           debug_print s;
99           false)
100     (* FIXME... they should type! *)
101     gl
102 ;;
103
104 let split_goals_with_metas metasenv subst gl =
105   List.partition 
106     (fun g ->
107       let _,context,ty = CicUtil.lookup_meta g metasenv in
108       let ty = CicMetaSubst.apply_subst subst ty in
109       CicUtil.is_meta_closed ty)
110     gl
111 ;;
112
113 let order_new_goals metasenv subst open_goals ppterm =
114   let prop,rest = split_goals_in_prop metasenv subst open_goals in
115   let closed_prop, open_prop = split_goals_with_metas metasenv subst prop in
116   let closed_type, open_type = split_goals_with_metas metasenv subst rest in
117   let open_goals =
118     (List.map (fun x -> x,P) (open_prop @ closed_prop)) 
119     @ 
120     (List.map (fun x -> x,T) (open_type @ closed_type))
121   in
122   let tys = 
123     List.map 
124       (fun (i,sort) -> 
125         let _,_,ty = CicUtil.lookup_meta i metasenv in i,ty,sort) open_goals 
126   in
127   debug_print (lazy ("   OPEN: "^
128     String.concat "\n" 
129       (List.map 
130          (function
131             | (i,t,P) -> string_of_int i   ^ ":"^ppterm t^ "Prop" 
132             | (i,t,T) -> string_of_int i  ^ ":"^ppterm t^ "Type")
133          tys)));
134   open_goals
135 ;;
136
137 let is_an_equational_goal = function
138   | Cic.Appl [Cic.MutInd(u,_,_);_;_;_] when LibraryObjects.is_eq_URI u -> true
139   | _ -> false
140 ;;
141
142 type auto_params = Cic.term list * (string * string) list 
143
144 let elems = ref [] ;;
145
146 (* closing a term w.r.t. its metavariables
147    very naif version: it does not take dependencies properly into account *)
148
149 let naif_closure ?(prefix_name="xxx_") t metasenv context =
150   let in_term t (i,_,_) =
151     List.exists (fun (j,_) -> j=i) (CicUtil.metas_of_term t)
152   in
153   let metasenv = List.filter (in_term t) metasenv in
154   let metasenv = ProofEngineHelpers.sort_metasenv metasenv in
155   let n = List.length metasenv in
156   let what = List.map (fun (i,cc,ty) -> Cic.Meta(i,[])) metasenv in
157   let _,with_what =
158     List.fold_left
159       (fun (i,acc) (_,cc,ty) -> (i-1,Cic.Rel i::acc)) 
160       (n,[]) metasenv 
161   in
162   let t = CicSubstitution.lift n t in
163   let body =
164     ProofEngineReduction.replace_lifting 
165       ~equality:(fun c t1 t2 ->
166          match t1,t2 with
167          | Cic.Meta(i,_),Cic.Meta(j,_) -> i = j
168          | _ -> false) 
169       ~context ~what ~with_what ~where:t 
170   in
171   let _, t =
172     List.fold_left
173       (fun (n,t) (_,cc,ty) -> 
174         n-1, Cic.Lambda(Cic.Name (prefix_name^string_of_int n),
175                CicSubstitution.lift n ty,t))
176       (n-1,body) metasenv 
177   in
178   t, List.length metasenv
179 ;;
180
181 let lambda_close ?prefix_name t menv ctx =
182   let t, num_lambdas = naif_closure ?prefix_name t menv ctx in
183     List.fold_left
184       (fun (t,i) -> function 
185         | None -> CicSubstitution.subst (Cic.Implicit None) t,i (* delift *)
186         | Some (name, Cic.Decl ty) -> Cic.Lambda (name, ty, t),i+1
187         | Some (name, Cic.Def (bo, ty)) -> Cic.LetIn (name, bo, ty, t),i+1)
188       (t,num_lambdas) ctx
189 ;;
190   
191 (* functions for retrieving theorems *)
192
193
194 exception FillingFailure of AutoCache.cache * AutomationCache.tables
195
196 let rec unfold context = function
197   | Cic.Prod(name,s,t) -> 
198       let t' = unfold ((Some (name,Cic.Decl s))::context) t in
199         Cic.Prod(name,s,t')        
200   | t -> ProofEngineReduction.unfold context t
201
202 let find_library_theorems dbd proof goal = 
203   let univ = MetadataQuery.universe_of_goal ~dbd false proof goal in
204   let terms = List.map CicUtil.term_of_uri univ in
205   List.map 
206     (fun t -> 
207        (t,fst(CicTypeChecker.type_of_aux' [] [] t CicUniv.oblivion_ugraph))) 
208     terms
209
210 let find_context_theorems context metasenv =
211   let l,_ =
212     List.fold_left
213       (fun (res,i) ctxentry ->
214          match ctxentry with
215            | Some (_,Cic.Decl t) -> 
216                (Cic.Rel i, CicSubstitution.lift i t)::res,i+1
217            | Some (_,Cic.Def (_,t)) ->
218                (Cic.Rel i, CicSubstitution.lift i t)::res,i+1
219            | None -> res,i+1)
220       ([],1) context
221   in l
222
223 let rec is_an_equality = function
224   | Cic.Appl [Cic.MutInd (uri, _, _); _; _; _] 
225     when (LibraryObjects.is_eq_URI uri) -> true
226   | Cic.Prod (_, _, t) -> is_an_equality t
227   | _ -> false
228 ;;
229
230 let partition_equalities =
231   List.partition (fun (_,ty) -> is_an_equality ty)
232
233
234 let default_auto tables _ cache _ _ _ _ = [],cache,tables ;; 
235
236 (* giusto per provare che succede 
237 let is_unit_equation context metasenv oldnewmeta term =
238   let head, metasenv, args, newmeta =
239     TermUtil.saturate_term oldnewmeta metasenv context term 0
240   in
241   let newmetas = 
242     List.filter (fun (i,_,_) -> i >= oldnewmeta) metasenv 
243   in
244     Some (args,metasenv,newmetas,head,newmeta) *)
245
246 let is_unit_equation context metasenv oldnewmeta term = 
247   let head, metasenv, args, newmeta =
248     TermUtil.saturate_term oldnewmeta metasenv context term 0
249   in
250   let propositional_args = 
251     HExtlib.filter_map
252       (function 
253       | Cic.Meta(i,_) -> 
254           let _,_,mt = CicUtil.lookup_meta i metasenv in
255           let sort,u = 
256             CicTypeChecker.type_of_aux' metasenv context mt 
257               CicUniv.oblivion_ugraph
258           in
259           if is_propositional context sort then Some i else None 
260       | _ -> assert false)
261     args
262   in
263     if propositional_args = [] then 
264       let newmetas = 
265         List.filter (fun (i,_,_) -> i >= oldnewmeta) metasenv 
266       in
267         Some (args,metasenv,newmetas,head,newmeta)
268     else None
269 ;;
270
271 let get_candidates skip_trie_filtering universe cache t =
272   let t = if skip_trie_filtering then Cic.Meta(0,[]) else t in
273   let candidates= 
274     (Universe.get_candidates universe t)@(AutoCache.get_candidates cache t)
275   in 
276   let debug_msg =
277     (lazy ("candidates for " ^ (CicPp.ppterm t) ^ " = " ^ 
278              (String.concat "\n" (List.map CicPp.ppterm candidates)))) in
279   debug_print debug_msg;
280   candidates
281 ;;
282
283 let only signature context metasenv t =
284   try
285     let ty,_ = 
286       CicTypeChecker.type_of_aux' metasenv context t CicUniv.oblivion_ugraph 
287     in
288     let consts = MetadataConstraints.constants_of ty in
289     let b = MetadataConstraints.UriManagerSet.subset consts signature in
290 (*     if b then (prerr_endline ("keeping " ^ (CicPp.ppterm t)); b)  *)
291     if b then b 
292     else
293       let ty' = unfold context ty in
294       let consts' = MetadataConstraints.constants_of ty' in
295       let b = MetadataConstraints.UriManagerSet.subset consts' signature  in
296 (*
297         if not b then prerr_endline ("filtering " ^ (CicPp.ppterm t))
298         else prerr_endline ("keeping " ^ (CicPp.ppterm t)); 
299 *)
300       b
301   with 
302   | CicTypeChecker.TypeCheckerFailure _ -> assert false
303   | ProofEngineTypes.Fail _ -> false (* unfold may fail *)
304 ;;
305
306 let not_default_eq_term t =
307   try
308     let uri = CicUtil.uri_of_term t in
309       not (LibraryObjects.in_eq_URIs uri)
310   with Invalid_argument _ -> true
311
312 let retrieve_equations dont_filter signature universe cache context metasenv =
313   match LibraryObjects.eq_URI() with
314     | None -> [] 
315     | Some eq_uri -> 
316         let eq_uri = UriManager.strip_xpointer eq_uri in
317         let fake= Cic.Meta(-1,[]) in
318         let fake_eq = Cic.Appl [Cic.MutInd (eq_uri,0, []);fake;fake;fake] in
319         let candidates = get_candidates false universe cache fake_eq in
320         if dont_filter then candidates
321         else let eq_uri = UriManager.uri_of_uriref eq_uri 0 None in
322           (* let candidates = List.filter not_default_eq_term candidates in *)
323           List.filter 
324             (only (MetadataConstraints.UriManagerSet.add eq_uri signature) 
325                context metasenv) candidates 
326
327 let build_equality bag head args proof newmetas = 
328   match head with
329   | Cic.Appl [Cic.MutInd (uri, _, _); ty; t1; t2] ->
330       let p =
331         if args = [] then proof else Cic.Appl (proof::args)
332       in 
333       let o = !Utils.compare_terms t1 t2 in
334       let stat = (ty,t1,t2,o) in
335       (* let w = compute_equality_weight stat in *)
336       let w = 0 in 
337       let proof = Equality.Exact p in
338       let bag, e = Equality.mk_equality bag (w, proof, stat, newmetas) in
339       (* to clean the local context of metas *)
340       Equality.fix_metas bag e
341   | _ -> assert false
342 ;;
343
344 let partition_unit_equalities context metasenv newmeta bag equations =
345   List.fold_left
346     (fun (bag,units,other,maxmeta)(t,ty) ->
347        if not (CicUtil.is_meta_closed t && CicUtil.is_meta_closed ty) then
348          let _ = 
349            HLog.warn 
350            ("Skipping " ^ CicMetaSubst.ppterm_in_context ~metasenv [] t context
351              ^ " since it is not meta closed")
352          in
353          bag, units,(t,ty)::other,maxmeta
354        else
355        match is_unit_equation context metasenv maxmeta ty with
356          | Some (args,metasenv,newmetas,head,newmeta') ->
357              let bag, equality =
358                build_equality bag head args t newmetas in
359              bag, equality::units,other,maxmeta
360          | None -> 
361              bag, units,(t,ty)::other,maxmeta)
362     (bag,[],[],newmeta) equations
363 ;;
364
365 let init_cache_and_tables 
366   ?dbd ~use_library ~use_context 
367   automation_cache restricted_univ (proof, goal) 
368 =
369   let _, metasenv, subst, _, _, _ = proof in
370   let _,context,_ = CicUtil.lookup_meta goal metasenv in
371   let add_list_to_tables metasenv subst automation_cache ct =
372     List.fold_left 
373       (fun automation_cache (t,_) -> 
374           AutomationCache.add_term_to_active automation_cache
375            metasenv subst context t None)
376       automation_cache ct
377   in
378   if restricted_univ = [] then
379     let ct = 
380       if use_context then find_context_theorems context metasenv else [] 
381     in
382     let lt = 
383       match use_library, dbd with
384       | true, Some dbd -> find_library_theorems dbd metasenv goal 
385       | _ -> []
386     in
387     let cache = AutoCache.cache_empty in
388     let cache = cache_add_list cache context (ct@lt) in  
389     let automation_cache = 
390       add_list_to_tables metasenv subst automation_cache ct 
391     in
392 (*     AutomationCache.pp_cache automation_cache; *)
393     automation_cache.AutomationCache.univ, 
394     automation_cache.AutomationCache.tables, 
395     cache
396   else
397     let t_ty = 
398       List.map
399         (fun  t ->
400           let ty, _ = CicTypeChecker.type_of_aux' 
401             metasenv ~subst:[] context t CicUniv.oblivion_ugraph
402           in
403             t, ty)
404         restricted_univ
405     in
406     (* let automation_cache = AutomationCache.empty () in *) 
407     let automation_cache = 
408       let universe = Universe.empty in
409       let universe = 
410         Universe.index_list universe context t_ty
411       in
412       { automation_cache with AutomationCache.univ = universe }
413     in
414     let ct = 
415      if use_context then find_context_theorems context metasenv else t_ty
416     in
417     let automation_cache = 
418       add_list_to_tables metasenv subst automation_cache ct
419     in
420     (* AutomationCache.pp_cache automation_cache; *)
421     automation_cache.AutomationCache.univ, 
422     automation_cache.AutomationCache.tables, 
423     cache_empty
424 ;;
425
426 let fill_hypothesis context metasenv subst term tables (universe:Universe.universe) cache auto fast = 
427   let actives, passives, bag = tables in 
428   let bag, head, metasenv, args = 
429     Equality.saturate_term bag metasenv subst context term 
430   in
431   let tables = actives, passives, bag in 
432   let propositional_args = 
433     HExtlib.filter_map
434       (function 
435       | Cic.Meta(i,_) -> 
436           let _,_,mt = CicUtil.lookup_meta i metasenv in
437           let sort,u = 
438             CicTypeChecker.type_of_aux' metasenv context mt 
439               CicUniv.oblivion_ugraph
440           in
441           if is_propositional context sort then Some i else None 
442       | _ -> assert false)
443     args
444   in
445   let results,cache,tables = 
446     if propositional_args = [] then 
447       let _,_,bag = tables in
448       let newmetas = Equality.filter_metasenv_gt_maxmeta bag metasenv in
449       [args,metasenv,newmetas,head],cache,tables
450     else
451       (*
452       let proof = 
453         None,metasenv,term,term (* term non e' significativo *)
454       in *)
455       let flags = 
456         if fast then
457           {AutoTypes.default_flags() with 
458            AutoTypes.timeout = Unix.gettimeofday() +. 1.0;
459            maxwidth = 2;maxdepth = 2;
460            use_paramod=true;use_only_paramod=false}
461         else
462           {AutoTypes.default_flags() with
463            AutoTypes.timeout = Unix.gettimeofday() +. 1.0;
464            maxwidth = 2;maxdepth = 4;
465            use_paramod=true;use_only_paramod=false} 
466       in
467       match auto tables universe cache context metasenv propositional_args flags with
468       | [],cache,tables -> raise (FillingFailure (cache,tables))
469       | substs,cache,tables ->
470           let actives, passaives, bag = tables in 
471           let bag, res = 
472           List.fold_right 
473             (fun subst (bag,acc) ->
474               let metasenv = 
475                 CicMetaSubst.apply_subst_metasenv subst metasenv
476               in
477               let head = CicMetaSubst.apply_subst subst head in
478               let newmetas = Equality.filter_metasenv_gt_maxmeta bag metasenv in
479               let args = List.map (CicMetaSubst.apply_subst subst) args in
480               let newm = CicMkImplicit.new_meta metasenv subst in
481               let bag = Equality.push_maxmeta bag newm in
482               bag, ((args,metasenv,newmetas,head) :: acc))
483             substs (bag,[])
484           in
485           let tables = actives, passives, bag in 
486            res, cache, tables
487   in
488   results,cache,tables
489 ;;
490
491 let build_equalities auto context metasenv subst tables universe cache equations =
492   List.fold_left 
493     (fun (tables,facts,cache) (t,ty) ->
494        (* in any case we add the equation to the cache *)
495        let cache = AutoCache.cache_add_list cache context [(t,ty)] in
496        try
497          let saturated, cache, tables = 
498            fill_hypothesis context metasenv subst ty tables universe cache auto true
499          in
500          let eqs, tables = 
501            List.fold_left 
502              (fun (acc, tables) (args,metasenv,newmetas,head) ->
503                 let actives, passives, bag = tables in 
504                 let bag, equality =
505                   build_equality bag head args t newmetas 
506                 in
507                 let tables = actives, passives, bag in
508                   equality::acc,tables)
509              ([],tables) saturated
510          in
511            (tables, eqs@facts, cache)
512        with FillingFailure (cache,tables) ->
513          (* if filling hypothesis fails we add the equation to
514             the cache *)
515          (tables,facts,cache)
516       )
517     (tables,[],cache) equations
518
519 let close_more tables context status auto signature universe cache =
520   let proof, goalno = status in
521   let _, metasenv,subst,_,_, _ = proof in  
522   let equations = 
523     retrieve_equations false signature universe cache context metasenv 
524   in
525   let eqs_and_types =
526     HExtlib.filter_map 
527       (fun t -> 
528          let ty,_ =
529            CicTypeChecker.type_of_aux' metasenv context t
530            CicUniv.oblivion_ugraph in
531            (* retrieve_equations could also return flexible terms *)
532            if is_an_equality ty then Some(t,ty) else None)
533       equations in
534   let tables, units, cache = 
535     build_equalities auto context metasenv subst tables universe cache eqs_and_types 
536   in
537   let active,passive,bag = tables in
538   let passive = Saturation.add_to_passive units passive in
539   let no = List.length units in
540   let active, passive, bag = 
541     Saturation.pump_actives context bag active passive (no+1) infinity
542   in 
543     (active,passive,bag), cache
544 ;;
545
546 let find_context_equalities dbd tables context proof (universe:Universe.universe) cache 
547 =
548   let module C = Cic in
549   let module S = CicSubstitution in
550   let module T = CicTypeChecker in
551   let _,metasenv,subst,_,_, _ = proof in
552   (* if use_auto is true, we try to close the hypothesis of equational
553     statements using auto; a naif, and probably wrong approach *)
554   let rec aux tables cache index = function
555     | [] -> tables, [], cache
556     | (Some (_, C.Decl (term)))::tl ->
557         debug_print
558           (lazy
559              (Printf.sprintf "Examining: %d (%s)" index (CicPp.ppterm term)));
560         let do_find tables context term =
561           match term with
562           | C.Prod (name, s, t) when is_an_equality t ->
563               (try 
564                 let term = S.lift index term in
565                 let saturated, cache, tables = 
566                   fill_hypothesis context metasenv subst term 
567                     tables universe cache default_auto false
568                 in
569                 let actives, passives, bag = tables in 
570                 let bag,eqs = 
571                   List.fold_left 
572                    (fun (bag,acc) (args,metasenv,newmetas,head) ->
573                      let bag, equality = 
574                        build_equality bag head args (Cic.Rel index) newmetas 
575                      in
576                      bag, equality::acc)
577                    (bag,[]) saturated
578                 in
579                 let tables = actives, passives, bag in
580                  tables, eqs, cache
581               with FillingFailure (cache,tables) ->
582                 tables, [], cache)
583           | C.Appl [C.MutInd (uri, _, _); ty; t1; t2]
584               when LibraryObjects.is_eq_URI uri ->
585               let term = S.lift index term in
586               let actives, passives, bag = tables in 
587               let bag, e = 
588                 build_equality bag term [] (Cic.Rel index) [] 
589               in
590               let tables = actives, passives, bag in
591               tables, [e], cache
592           | _ -> tables, [], cache
593         in 
594         let tables, eqs, cache = do_find tables context term in
595         let tables, rest, cache = aux tables cache (index+1) tl in
596         tables, List.map (fun x -> index,x) eqs @ rest, cache
597     | _::tl ->
598         aux tables cache (index+1) tl
599   in
600   let tables, il, cache = aux tables cache 1 context in
601   let indexes, equalities = List.split il in
602   tables, indexes, equalities, cache
603 ;;
604
605 (********** PARAMETERS PASSING ***************)
606
607 let bool params name default =
608     try 
609       let s = List.assoc name params in 
610       if s = "" || s = "1" || s = "true" || s = "yes" || s = "on" then true
611       else if s = "0" || s = "false" || s = "no" || s= "off" then false
612       else 
613         let msg = "Unrecognized value for parameter "^name^"\n" in
614         let msg = msg^"Accepted values are 1,true,yes,on and 0,false,no,off" in
615         raise (ProofEngineTypes.Fail (lazy msg))
616     with Not_found -> default
617 ;; 
618
619 let string params name default =
620     try List.assoc name params with
621     | Not_found -> default
622 ;; 
623
624 let int params name default =
625     try int_of_string (List.assoc name params) with
626     | Not_found -> default
627     | Failure _ -> 
628         raise (ProofEngineTypes.Fail (lazy (name ^ " must be an integer")))
629 ;;  
630
631 let flags_of_params params ?(for_applyS=false) () =
632  let int = int params in
633  let bool = bool params in
634  let close_more = bool "close_more" false in
635  let use_paramod = bool "use_paramod" true in
636  let skip_trie_filtering = bool "skip_trie_filtering" false in
637  let skip_context = bool "skip_context" false in
638  let use_only_paramod =
639   if for_applyS then true else bool "paramodulation" false in
640  let use_library = bool "library"  
641    ((AutoTypes.default_flags()).AutoTypes.use_library) in
642  let depth = int "depth" ((AutoTypes.default_flags()).AutoTypes.maxdepth) in
643  let width = int "width" ((AutoTypes.default_flags()).AutoTypes.maxwidth) in
644  let size = int "size" ((AutoTypes.default_flags()).AutoTypes.maxsize) in
645  let gsize = int "gsize" ((AutoTypes.default_flags()).AutoTypes.maxgoalsizefactor) in
646  let do_type = bool "type" false in
647  let timeout = int "timeout" 0 in
648   { AutoTypes.maxdepth = 
649       if use_only_paramod then 2 else depth;
650     AutoTypes.maxwidth = width;
651     AutoTypes.maxsize = size;
652     AutoTypes.timeout = 
653       if timeout = 0 then
654        if for_applyS then Unix.gettimeofday () +. 30.0
655        else
656          infinity
657       else
658        Unix.gettimeofday() +. (float_of_int timeout);
659     AutoTypes.use_library = use_library; 
660     AutoTypes.use_paramod = use_paramod;
661     AutoTypes.use_only_paramod = use_only_paramod;
662     AutoTypes.close_more = close_more;
663     AutoTypes.dont_cache_failures = false;
664     AutoTypes.maxgoalsizefactor = gsize;
665     AutoTypes.do_types = do_type;
666     AutoTypes.skip_trie_filtering = skip_trie_filtering;
667     AutoTypes.skip_context = skip_context;
668   }
669
670
671 let eq_of_goal = function
672   | Cic.Appl [Cic.MutInd(uri,0,_);_;_;_] when LibraryObjects.is_eq_URI uri ->
673       uri
674   | _ -> raise (ProofEngineTypes.Fail (lazy ("The goal is not an equality ")))
675 ;;
676
677 (* performs steps of rewrite with the universe, obtaining if possible 
678  * a trivial goal *)
679 let solve_rewrite ~automation_cache ~params:(univ,params) (proof,goal)= 
680   let steps = int_of_string (string params "steps" "4") in 
681   let use_context = bool params "use_context" true in 
682   let universe, tables, cache =
683    init_cache_and_tables ~use_library:false ~use_context
684      automation_cache univ (proof,goal) 
685   in
686   let actives, passives, bag = tables in 
687   let pa,metasenv,subst,pb,pc,pd = proof in
688   let _,context,ty = CicUtil.lookup_meta goal metasenv in
689   let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
690   let context = CicMetaSubst.apply_subst_context subst context in
691   let ty = CicMetaSubst.apply_subst subst ty in
692   let eq_uri = eq_of_goal ty in
693   let initgoal = [], metasenv, ty in
694   let table = 
695     let equalities = (Saturation.list_of_passive passives) in
696     List.fold_left (fun tbl eq -> Indexing.index tbl eq) (snd actives) equalities
697   in
698   let env = metasenv,context,CicUniv.oblivion_ugraph in
699   debug_print (lazy ("demod to solve: " ^ CicPp.ppterm ty));
700   match Indexing.solve_demodulating bag env table initgoal steps with 
701   | Some (bag, gproof, metasenv, sub_subst, proof) ->
702       let subst_candidates,extra_infos = 
703         List.split 
704           (HExtlib.filter_map 
705              (fun (i,c,_) -> 
706                 if i <> goal && c = context then Some (i,(c,ty)) else None) 
707              metasenv)
708       in
709       let proofterm,proto_subst = 
710         let proof = Equality.add_subst sub_subst proof in
711         Equality.build_goal_proof 
712           bag eq_uri gproof proof ty subst_candidates context metasenv
713       in
714       let proofterm = Subst.apply_subst sub_subst proofterm in
715       let extrasubst = 
716         HExtlib.filter_map
717           (fun (i,((c,ty),t)) -> 
718              match t with
719              | Cic.Meta (j,_) when i=j -> None
720              | _ -> Some (i,(c,t,ty)))
721           (List.combine subst_candidates 
722             (List.combine extra_infos proto_subst))
723       in
724       let subst = subst @ extrasubst in
725       let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
726       let proofterm, _, metasenv,subst, _ =
727         CicRefine.type_of metasenv subst context proofterm
728           CicUniv.oblivion_ugraph
729       in
730       let status = (pa,metasenv,subst,pb,pc,pd), goal in
731       ProofEngineTypes.apply_tactic 
732         (PrimitiveTactics.apply_tac ~term:proofterm) status
733   | None -> 
734       raise 
735         (ProofEngineTypes.Fail (lazy 
736           ("Unable to solve with " ^ string_of_int steps ^ " demodulations")))
737 ;;
738
739 (* Demodulate thorem *)
740 let open_type ty bo =
741   let rec open_type_aux context ty k args =
742     match ty with 
743       | Cic.Prod (n,s,t) ->
744           let n' = 
745             FreshNamesGenerator.mk_fresh_name [] context n ~typ:s ~subst:[] in
746           let entry = match n' with
747             | Cic.Name _    -> Some (n',(Cic.Decl s))
748             | Cic.Anonymous -> None
749           in
750             open_type_aux (entry::context) t (k+1) ((Cic.Rel k)::args)
751       | Cic.LetIn (n,s,sty,t) ->
752           let entry = Some (n,(Cic.Def (s,sty)))
753           in
754             open_type_aux (entry::context) t (k+1) args
755       | _  -> context, ty, args
756   in
757   let context, ty, args = open_type_aux [] ty 1 [] in
758   match args with
759     | [] -> context, ty, bo
760     | _ -> context, ty, Cic.Appl (bo::args)
761 ;; 
762
763 let rec close_type bo ty context =
764   match context with 
765     | [] -> assert_proof_is_valid bo [] [] ty; (bo,ty)
766     | Some (n,(Cic.Decl s))::tl ->
767         close_type (Cic.Lambda (n,s,bo)) (Cic.Prod (n,s,ty)) tl
768     | Some (n,(Cic.Def (s,sty)))::tl ->
769         close_type (Cic.LetIn (n,s,sty,bo)) (Cic.LetIn (n,s,sty,ty)) tl
770     | _ -> assert false
771 ;; 
772
773 let is_subsumed univ context ty =
774   let candidates = Universe.get_candidates univ ty in
775     List.fold_left 
776       (fun res cand ->
777          match res with
778            | Some found -> Some found
779            | None -> 
780                try 
781                  let mk_irl = 
782                    CicMkImplicit.identity_relocation_list_for_metavariable in
783                  let metasenv = [(0,context,ty)] in
784                  let fake_proof = 
785                    None,metasenv,[] , (lazy (Cic.Meta(0,mk_irl context))),ty,[]
786                  in
787                  let (_,metasenv,subst,_,_,_), open_goals =
788                    ProofEngineTypes.apply_tactic 
789                      (PrimitiveTactics.apply_tac ~term:cand) 
790                      (fake_proof,0)
791                  in
792                  let prop_goals, other = 
793                    split_goals_in_prop metasenv subst open_goals 
794                  in
795                   if prop_goals = [] then Some cand else None
796                with 
797                  | ProofEngineTypes.Fail s -> None
798                  | CicUnification.Uncertain s ->  None
799       ) None candidates
800 ;;
801
802 let demodulate_theorem ~automation_cache uri =
803   let eq_uri = 
804     match LibraryObjects.eq_URI () with
805       | Some (uri) -> uri
806       | None -> raise (ProofEngineTypes.Fail (lazy "equality not declared")) in
807   let obj,_ = CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
808   in
809   let context,ty,bo =
810     match obj with 
811       | Cic.Constant(n, _, ty ,_, _) -> open_type ty (Cic.Const(uri,[]))
812       | _ -> raise (ProofEngineTypes.Fail (lazy "not a theorem"))
813   in
814   if CicUtil.is_closed ty then 
815     raise (ProofEngineTypes.Fail (lazy ("closed term: dangerous reduction")));
816   let initgoal = [], [], ty in
817   (* compute the signature *)
818   let signature = 
819     let ty_set = MetadataConstraints.constants_of ty in
820     let hyp_set = MetadataQuery.signature_of_hypothesis context [] in
821     let set = MetadataConstraints.UriManagerSet.union ty_set hyp_set in
822       MetadataQuery.close_with_types set [] context 
823   in
824   (* retrieve equations from the universe universe *)
825   (* XXX automation_cache *)
826   let universe = automation_cache.AutomationCache.univ in
827   let equations = 
828     retrieve_equations true signature universe AutoCache.cache_empty context []
829   in
830   debug_print 
831     (lazy ("ho trovato equazioni n. "^(string_of_int (List.length equations))));
832   let eqs_and_types =
833     HExtlib.filter_map 
834       (fun t -> 
835          let ty,_ =
836            CicTypeChecker.type_of_aux' [] context t CicUniv.oblivion_ugraph
837          in
838          (* retrieve_equations could also return flexible terms *)
839          if is_an_equality ty then Some(t,ty) 
840          else
841            try
842              let ty' = unfold context ty in
843              if is_an_equality ty' then Some(t,ty') else None
844            with ProofEngineTypes.Fail _ -> None) 
845       equations
846   in
847   let bag = Equality.mk_equality_bag () in
848
849   let bag, units, _, newmeta = 
850     partition_unit_equalities context [] (CicMkImplicit.new_meta [] []) bag eqs_and_types 
851   in
852   let table =
853     List.fold_left 
854       (fun tbl eq -> Indexing.index tbl eq) 
855       Indexing.empty units
856   in 
857   let changed,(newproof,newmetasenv, newty) =
858     Indexing.demod bag
859       ([],context,CicUniv.oblivion_ugraph) table initgoal in
860   if changed then
861     begin
862       let oldproof = Equality.Exact bo in
863       let proofterm,_ = 
864         Equality.build_goal_proof (~contextualize:false) (~forward:true) bag
865           eq_uri newproof oldproof ty [] context newmetasenv
866       in
867       if newmetasenv <> [] then 
868         raise (ProofEngineTypes.Fail (lazy ("metasenv not empty")))
869       else
870         begin
871           assert_proof_is_valid proofterm newmetasenv context newty;
872           match is_subsumed universe context newty with
873             | Some t -> raise 
874                 (ProofEngineTypes.Fail (lazy ("subsumed by " ^ CicPp.ppterm t)))
875             | None -> close_type proofterm newty context 
876         end
877     end
878   else (* if newty = ty then *)
879     raise (ProofEngineTypes.Fail (lazy "no progress"))
880   (*else ProofEngineTypes.apply_tactic 
881     (ReductionTactics.simpl_tac
882       ~pattern:(ProofEngineTypes.conclusion_pattern None)) initialstatus*)
883 ;;      
884
885
886 (* NEW DEMODULATE *)
887 let demodulate ~dbd ~automation_cache ~params:(univ, params) (proof,goal)= 
888   let universe, tables, cache =
889      init_cache_and_tables 
890        ~dbd ~use_library:false ~use_context:true
891        automation_cache univ (proof,goal) 
892   in
893   let eq_uri = 
894     match LibraryObjects.eq_URI () with
895       | Some (uri) -> uri
896       | None -> raise (ProofEngineTypes.Fail (lazy "equality not declared")) in
897   let active, passive, bag = tables in
898   let curi,metasenv,subst,pbo,pty, attrs = proof in
899   let metano,context,ty = CicUtil.lookup_meta goal metasenv in
900   let irl = CicMkImplicit.identity_relocation_list_for_metavariable context in
901   let initgoal = [], metasenv, ty in
902   let equalities = (Saturation.list_of_passive passive) in
903   (* we demodulate using both actives passives *)
904   let env = metasenv,context,CicUniv.empty_ugraph in
905   debug_print (lazy ("PASSIVES:" ^ string_of_int(List.length equalities)));
906   List.iter (fun e -> debug_print (lazy (Equality.string_of_equality ~env e)))
907     equalities;
908   let table = 
909     List.fold_left 
910       (fun tbl eq -> Indexing.index tbl eq) 
911       (snd active) equalities
912   in
913   let changed,(newproof,newmetasenv, newty) =
914     (* Indexing.demodulation_goal bag *)
915       Indexing.demod bag
916       (metasenv,context,CicUniv.oblivion_ugraph) table initgoal 
917   in
918   if changed then
919     begin
920       let maxm = CicMkImplicit.new_meta metasenv subst in
921       let opengoal = Equality.Exact (Cic.Meta(maxm,irl)) in
922       let subst_candidates = List.map (fun (i,_,_) -> i) metasenv in
923       let subst_candidates = List.filter (fun x-> x <> goal) subst_candidates in
924       let proofterm, proto_subst = 
925         Equality.build_goal_proof (~contextualize:false) bag
926           eq_uri newproof opengoal ty subst_candidates context metasenv
927       in
928       (* XXX understan what to do with proto subst *)
929       let metasenv = (maxm,context,newty)::metasenv in
930       let proofterm, _, metasenv, subst, _ =
931         CicRefine.type_of metasenv subst context proofterm
932           CicUniv.oblivion_ugraph
933       in
934       let extended_status = (curi,metasenv,subst,pbo,pty, attrs),goal in
935       let proof,gl = 
936         ProofEngineTypes.apply_tactic 
937           (PrimitiveTactics.apply_tac ~term:proofterm) extended_status
938       in
939         proof,maxm::gl
940     end
941   else 
942     raise (ProofEngineTypes.Fail (lazy "no progress"))
943 ;;
944
945 let demodulate_tac ~dbd ~params:(_,flags as params) ~automation_cache =
946  ProofEngineTypes.mk_tactic 
947   (fun status -> 
948     let all = bool flags "all" false in
949     if all then
950       solve_rewrite ~params ~automation_cache status
951     else
952       demodulate ~dbd ~params ~automation_cache status)
953 ;;
954 (***************** applyS *******************)
955
956 let apply_smart_aux 
957  dbd automation_cache params proof goal newmeta' metasenv' subst
958   context term' ty termty goal_arity 
959
960  let consthead,newmetasenv,arguments,_ =
961    TermUtil.saturate_term newmeta' metasenv' context termty goal_arity in
962  let term'' = 
963    match arguments with 
964    | [] -> term' 
965    | _ -> Cic.Appl (term'::arguments) 
966  in
967  let consthead = 
968    let rec aux t = function
969      | [] -> 
970         let t = CicReduction.normalize ~delta:false context t in
971         (match t, ty with
972         | Cic.Appl (hd1::_), Cic.Appl (hd2::_) when hd1 <> hd2 ->
973              let t = ProofEngineReduction.unfold context t in
974              (match t with
975              | Cic.Appl (hd1'::_) when hd1' = hd2 -> t
976              | _ -> raise (ProofEngineTypes.Fail (lazy "incompatible head")))
977         | _ -> t)
978      | arg :: tl -> 
979          match CicReduction.whd context t with
980          | Cic.Prod (_,_,tgt) -> 
981              aux (CicSubstitution.subst arg tgt) tl
982          | _ -> assert false
983    in
984     aux termty arguments
985  in
986  let goal_for_paramod =
987   match LibraryObjects.eq_URI () with
988   | Some uri -> 
989       Cic.Appl [Cic.MutInd (uri,0,[]); Cic.Implicit (Some `Type); consthead; ty]
990   | None -> raise (ProofEngineTypes.Fail (lazy "No equality defined"))
991  in
992  try 
993    let goal_for_paramod, _, newmetasenv, subst, _ = 
994      CicRefine.type_of newmetasenv subst context goal_for_paramod 
995        CicUniv.oblivion_ugraph
996    in
997    let newmeta = CicMkImplicit.new_meta newmetasenv subst in
998    let metasenv_for_paramod = (newmeta,context,goal_for_paramod)::newmetasenv in
999    let proof'' = 
1000      let uri,_,_,p,ty, attrs = proof in 
1001      uri,metasenv_for_paramod,subst,p,ty, attrs 
1002    in
1003    let irl = CicMkImplicit.identity_relocation_list_for_metavariable context in
1004 (*
1005    prerr_endline ("------ prima di rewrite su ------ " ^ string_of_int goal);
1006    prerr_endline ("menv:\n"^CicMetaSubst.ppmetasenv [] metasenv_for_paramod);
1007    prerr_endline ("subst:\n"^CicMetaSubst.ppsubst
1008      ~metasenv:(metasenv_for_paramod)
1009      subst);
1010 *)
1011
1012    let (proof''',goals) =
1013       ProofEngineTypes.apply_tactic 
1014         (EqualityTactics.rewrite_tac ~direction:`RightToLeft
1015         ~pattern:(ProofEngineTypes.conclusion_pattern None)
1016         (Cic.Meta(newmeta,irl)) []) (proof'',goal)
1017    in
1018    let goal = match goals with [g] -> g | _ -> assert false in
1019    let  proof'''', _  =
1020      ProofEngineTypes.apply_tactic 
1021        (PrimitiveTactics.apply_tac term'')
1022        (proof''',goal) 
1023    in
1024
1025
1026    let (_,m,_,_,_,_ as p) = 
1027         let pu,metasenv,subst,proof,px,py = proof'''' in
1028         let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
1029         let proof'''' = pu,metasenv,subst,proof,px,py in
1030         let univ, params = params in
1031         let use_context = bool params "use_context" true in 
1032         let universe, (active,passive,bag), cache =
1033          init_cache_and_tables ~use_library:false ~use_context
1034            automation_cache univ (proof'''',newmeta)
1035         in
1036         match
1037           Saturation.solve_narrowing bag (proof'''',newmeta) active passive 
1038             1 (*0 infinity*)
1039         with 
1040           | None, active, passive, bag -> 
1041               raise (ProofEngineTypes.Fail (lazy ("paramod fails")))
1042           | Some(subst',(pu,metasenv,_,proof,px, py),open_goals),active,
1043             passive,bag ->
1044               assert_subst_are_disjoint subst subst';
1045               let subst = subst@subst' in
1046               pu,metasenv,subst,proof,px,py
1047    in
1048
1049 (*
1050    let (_,m,_,_,_,_ as p),_ = 
1051       solve_rewrite ~params ~automation_cache (proof'''',newmeta)
1052    in
1053 *)
1054
1055    let open_goals = 
1056      ProofEngineHelpers.compare_metasenvs ~oldmetasenv:metasenv' ~newmetasenv:m
1057    in
1058    p, open_goals 
1059  with
1060    CicRefine.RefineFailure msg -> 
1061      raise (ProofEngineTypes.Fail msg)
1062 ;;
1063
1064 let apply_smart 
1065   ~dbd ~term ~automation_cache ~params (proof, goal) 
1066 =
1067  let module T = CicTypeChecker in
1068  let module R = CicReduction in
1069  let module C = Cic in
1070   let (_,metasenv,subst,_,_, _) = proof in
1071   let metano,context,ty = CicUtil.lookup_meta goal metasenv in
1072   let newmeta = CicMkImplicit.new_meta metasenv subst in
1073    let exp_named_subst_diff,newmeta',newmetasenvfragment,term' =
1074     match term with
1075        C.Var (uri,exp_named_subst) ->
1076         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1077          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1078           exp_named_subst
1079         in
1080          exp_named_subst_diff,newmeta',newmetasenvfragment,
1081           C.Var (uri,exp_named_subst')
1082      | C.Const (uri,exp_named_subst) ->
1083         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1084          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1085           exp_named_subst
1086         in
1087          exp_named_subst_diff,newmeta',newmetasenvfragment,
1088           C.Const (uri,exp_named_subst')
1089      | C.MutInd (uri,tyno,exp_named_subst) ->
1090         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1091          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1092           exp_named_subst
1093         in
1094          exp_named_subst_diff,newmeta',newmetasenvfragment,
1095           C.MutInd (uri,tyno,exp_named_subst')
1096      | C.MutConstruct (uri,tyno,consno,exp_named_subst) ->
1097         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1098          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1099           exp_named_subst
1100         in
1101          exp_named_subst_diff,newmeta',newmetasenvfragment,
1102           C.MutConstruct (uri,tyno,consno,exp_named_subst')
1103      | _ -> [],newmeta,[],term
1104    in
1105    let metasenv' = metasenv@newmetasenvfragment in
1106    let termty,_ = 
1107      CicTypeChecker.type_of_aux' 
1108       metasenv' ~subst context term' CicUniv.oblivion_ugraph
1109    in
1110    let termty = CicSubstitution.subst_vars exp_named_subst_diff termty in
1111    let goal_arity = 
1112      let rec count_prods context ty =
1113       match CicReduction.whd ~subst context ty with
1114       | Cic.Prod (n,s,t) -> 1 + count_prods (Some (n,Cic.Decl s)::context) t
1115       | _ -> 0
1116      in
1117        count_prods context ty
1118    in
1119     apply_smart_aux dbd automation_cache params proof goal 
1120      newmeta' metasenv' subst context term' ty termty goal_arity
1121 ;;
1122
1123 let applyS_tac ~dbd ~term ~params ~automation_cache =
1124  ProofEngineTypes.mk_tactic
1125   (fun status ->
1126     try 
1127       apply_smart ~dbd ~term ~params ~automation_cache status
1128     with 
1129     | CicUnification.UnificationFailure msg
1130     | CicTypeChecker.TypeCheckerFailure msg ->
1131         raise (ProofEngineTypes.Fail msg))
1132 ;;
1133
1134
1135 (****************** AUTO ********************)
1136
1137 let calculate_timeout flags = 
1138     if flags.timeout = 0. then 
1139       (debug_print (lazy "AUTO WITH NO TIMEOUT");
1140        {flags with timeout = infinity})
1141     else 
1142       flags 
1143 ;;
1144 let is_equational_case goalty flags =
1145   let ensure_equational t = 
1146     if is_an_equational_goal t then true 
1147     else false
1148   in
1149   (flags.use_paramod && is_an_equational_goal goalty) || 
1150   (flags.use_only_paramod && ensure_equational goalty)
1151 ;;
1152
1153 type menv = Cic.metasenv
1154 type subst = Cic.substitution
1155 type goal = ProofEngineTypes.goal * int * AutoTypes.sort
1156 let candidate_no = ref 0;;
1157 type candidate = int * Cic.term Lazy.t
1158 type cache = AutoCache.cache
1159
1160 type fail = 
1161   (* the goal (mainly for depth) and key of the goal *)
1162   goal * AutoCache.cache_key
1163 type op = 
1164   (* goal has to be proved *)
1165   | D of goal 
1166   (* goal has to be cached as a success obtained using candidate as the first
1167    * step *)
1168   | S of goal * AutoCache.cache_key * candidate * int 
1169 type elem = 
1170   (* menv, subst, size, operations done (only S), operations to do, failures to cache if any op fails *)
1171   menv * subst * int * op list * op list * fail list 
1172 type status = 
1173   (* list of computations that may lead to the solution: all op list will
1174    * end with the same (S(g,_)) *)
1175   elem list
1176 type auto_result = 
1177   (* menv, subst, alternatives, tables, cache *)
1178   | Proved of menv * subst * elem list * AutomationCache.tables * cache 
1179   | Gaveup of AutomationCache.tables * cache 
1180
1181
1182 (* the status exported to the external observer *)  
1183 type auto_status = 
1184   (* context, (goal,candidate) list, and_list, history *)
1185   Cic.context * (int * Cic.term * bool * int * (int * Cic.term Lazy.t) list) list * 
1186   (int * Cic.term * int) list * Cic.term Lazy.t list
1187
1188 let d_prefix l =
1189   let rec aux acc = function
1190     | (D g)::tl -> aux (acc@[g]) tl
1191     | _ -> acc
1192   in
1193     aux [] l
1194 ;;
1195 let prop_only l =
1196   List.filter (function (_,_,P) -> true | _ -> false) l
1197 ;;
1198
1199 let d_goals l =
1200   let rec aux acc = function
1201     | (D g)::tl -> aux (acc@[g]) tl
1202     | (S _)::tl -> aux acc tl
1203     | [] -> acc
1204   in
1205     aux [] l
1206 ;;
1207
1208 let calculate_goal_ty (goalno,_,_) s m = 
1209   try
1210     let _,cc,goalty = CicUtil.lookup_meta goalno m in
1211     (* XXX applicare la subst al contesto? *)
1212     Some (cc, CicMetaSubst.apply_subst s goalty)
1213   with CicUtil.Meta_not_found i when i = goalno -> None
1214 ;;
1215
1216 let calculate_closed_goal_ty (goalno,_,_) s = 
1217   try
1218     let cc,_,goalty = List.assoc goalno s in
1219     (* XXX applicare la subst al contesto? *)
1220     Some (cc, CicMetaSubst.apply_subst s goalty)
1221   with Not_found -> 
1222     None
1223 ;;
1224
1225 let pp_status ctx status = 
1226   if debug then 
1227   let names = Utils.names_of_context ctx in
1228   let pp x = 
1229     let x = 
1230       ProofEngineReduction.replace 
1231         ~equality:(fun a b -> match b with Cic.Meta _ -> true | _ -> false) 
1232           ~what:[Cic.Rel 1] ~with_what:[Cic.Implicit None] ~where:x
1233     in
1234     CicPp.pp x names
1235   in
1236   let string_of_do m s (gi,_,_ as g) d =
1237     match calculate_goal_ty g s m with
1238     | Some (_,gty) -> Printf.sprintf "D(%d, %s, %d)" gi (pp gty) d
1239     | None -> Printf.sprintf "D(%d, _, %d)" gi d
1240   in
1241   let string_of_s m su k (ci,ct) gi =
1242     Printf.sprintf "S(%d, %s, %s, %d)" gi (pp k) (pp (Lazy.force ct)) ci
1243   in
1244   let string_of_ol m su l =
1245     String.concat " | " 
1246       (List.map 
1247         (function 
1248           | D (g,d,s) -> string_of_do m su (g,d,s) d 
1249           | S ((gi,_,_),k,c,_) -> string_of_s m su k c gi) 
1250         l)
1251   in
1252   let string_of_fl m s fl = 
1253     String.concat " | " 
1254       (List.map (fun ((i,_,_),ty) -> 
1255          Printf.sprintf "(%d, %s)" i (pp ty)) fl)
1256   in
1257   let rec aux = function
1258     | [] -> ()
1259     | (m,s,_,_,ol,fl)::tl ->
1260         Printf.eprintf "< [%s] ;;; [%s]>\n" 
1261           (string_of_ol m s ol) (string_of_fl m s fl);
1262         aux tl
1263   in
1264     Printf.eprintf "-------------------------- status -------------------\n";
1265     aux status;
1266     Printf.eprintf "-----------------------------------------------------\n";
1267 ;;
1268   
1269 let auto_status = ref [] ;;
1270 let auto_context = ref [];;
1271 let in_pause = ref false;;
1272 let pause b = in_pause := b;;
1273 let cond = Condition.create ();;
1274 let mutex = Mutex.create ();;
1275 let hint = ref None;;
1276 let prune_hint = ref [];;
1277
1278 let step _ = Condition.signal cond;;
1279 let give_hint n = hint := Some n;;
1280 let give_prune_hint hint =
1281   prune_hint := hint :: !prune_hint
1282 ;;
1283
1284 let check_pause _ =
1285   if !in_pause then
1286     begin
1287       Mutex.lock mutex;
1288       Condition.wait cond mutex;
1289       Mutex.unlock mutex
1290     end
1291 ;;
1292
1293 let get_auto_status _ = 
1294   let status = !auto_status in
1295   let and_list,elems,last = 
1296     match status with
1297     | [] -> [],[],[]
1298     | (m,s,_,don,gl,fail)::tl ->
1299         let and_list = 
1300           HExtlib.filter_map 
1301             (fun (id,d,_ as g) -> 
1302               match calculate_goal_ty g s m with
1303               | Some (_,x) -> Some (id,x,d) | None -> None)
1304             (d_goals gl)
1305         in
1306         let rows = 
1307           (* these are the S goalsin the or list *)
1308           let orlist = 
1309             List.map
1310               (fun (m,s,_,don,gl,fail) -> 
1311                 HExtlib.filter_map
1312                   (function S (g,k,c,_) -> Some (g,k,c) | _ -> None) 
1313                   (List.rev don @ gl))
1314               status
1315           in
1316           (* this function eats id from a list l::[id,x] returning x, l *)
1317           let eat_tail_if_eq id l = 
1318             let rec aux (s, l) = function
1319               | [] -> s, l
1320               | ((id1,_,_),k1,c)::tl when id = id1 ->
1321                   (match s with
1322                   | None -> aux (Some c,l) tl
1323                   | Some _ -> assert false)
1324               | ((id1,_,_),k1,c as e)::tl -> aux (s, e::l) tl
1325             in
1326             let c, l = aux (None, []) l in
1327             c, List.rev l
1328           in
1329           let eat_in_parallel id l =
1330             let rec aux (b,eaten, new_l as acc) l =
1331               match l with
1332               | [] -> acc
1333               | l::tl ->
1334                   match eat_tail_if_eq id l with
1335                   | None, l -> aux (b@[false], eaten, new_l@[l]) tl
1336                   | Some t,l -> aux (b@[true],eaten@[t], new_l@[l]) tl
1337             in
1338             aux ([],[],[]) l
1339           in
1340           let rec eat_all rows l =
1341             match l with
1342             | [] -> rows
1343             | elem::or_list ->
1344                 match List.rev elem with
1345                 | ((to_eat,depth,_),k,_)::next_lunch ->
1346                     let b, eaten, l = eat_in_parallel to_eat l in
1347                     let eaten = HExtlib.list_uniq eaten in
1348                     let eaten = List.rev eaten in
1349                     let b = true (* List.hd (List.rev b) *) in
1350                     let rows = rows @ [to_eat,k,b,depth,eaten] in
1351                     eat_all rows l
1352                 | [] -> eat_all rows or_list
1353           in
1354           eat_all [] (List.rev orlist)
1355         in
1356         let history = 
1357           HExtlib.filter_map
1358             (function (S (_,_,(_,c),_)) -> Some c | _ -> None) 
1359             gl 
1360         in
1361 (*         let rows = List.filter (fun (_,l) -> l <> []) rows in *)
1362         and_list, rows, history
1363   in
1364   !auto_context, elems, and_list, last
1365 ;;
1366
1367 (* Works if there is no dependency over proofs *)
1368 let is_a_green_cut goalty =
1369   CicUtil.is_meta_closed goalty
1370 ;;
1371 let rec first_s = function
1372   | (D _)::tl -> first_s tl
1373   | (S (g,k,c,s))::tl -> Some ((g,k,c,s),tl)
1374   | [] -> None
1375 ;;
1376 let list_union l1 l2 =
1377   (* TODO ottimizzare compare *)
1378   HExtlib.list_uniq (List.sort compare (l1 @ l1))
1379 ;;
1380 let rec eq_todo l1 l2 =
1381   match l1,l2 with
1382   | (D g1) :: tl1,(D g2) :: tl2 when g1=g2 -> eq_todo tl1 tl2
1383   | (S (g1,k1,(c1,lt1),i1)) :: tl1, (S (g2,k2,(c2,lt2),i2)) :: tl2
1384     when i1 = i2 && g1 = g2 && k1 = k2 && c1 = c2 ->
1385       if Lazy.force lt1 = Lazy.force lt2 then eq_todo tl1 tl2 else false
1386   | [],[] -> true
1387   | _ -> false
1388 ;;
1389 let eat_head todo id fl orlist = 
1390   let rec aux acc = function
1391   | [] -> [], acc
1392   | (m, s, _, _, todo1, fl1)::tl as orlist -> 
1393       let rec aux1 todo1 =
1394         match first_s todo1 with
1395         | None -> orlist, acc
1396         | Some (((gno,_,_),_,_,_), todo11) ->
1397             (* TODO confronto tra todo da ottimizzare *)
1398             if gno = id && eq_todo todo11 todo then 
1399               aux (list_union fl1 acc) tl
1400             else 
1401               aux1 todo11
1402       in
1403        aux1 todo1
1404   in 
1405     aux fl orlist
1406 ;;
1407 let close_proof p ty menv context = 
1408   let metas =
1409     List.map fst (CicUtil.metas_of_term p @ CicUtil.metas_of_term ty)
1410   in
1411   let menv = List.filter (fun (i,_,_) -> List.exists ((=)i) metas) menv in
1412   naif_closure p menv context
1413 ;;
1414 (* XXX capire bene quando aggiungere alla cache *)
1415 let add_to_cache_and_del_from_orlist_if_green_cut
1416   g s m cache key todo orlist fl ctx size minsize
1417
1418   let cache = cache_remove_underinspection cache key in
1419   (* prima per fare la irl usavamo il contesto vero e proprio e non quello 
1420    * canonico! XXX *)
1421   match calculate_closed_goal_ty g s with
1422   | None -> assert false
1423   | Some (canonical_ctx , gty) ->
1424       let goalno,depth,sort = g in
1425       let irl = mk_irl canonical_ctx in
1426       let goal = Cic.Meta(goalno, irl) in
1427       let proof = CicMetaSubst.apply_subst s goal in
1428       let green_proof, closed_proof = 
1429         let b = is_a_green_cut proof in
1430         if not b then
1431           b, (* close_proof proof gty m ctx *) proof 
1432         else
1433           b, proof
1434       in
1435       debug_print (lazy ("TENTATIVE CACHE: " ^ CicPp.ppterm key));
1436       if is_a_green_cut key then
1437         (* if the initia goal was closed, we cut alternatives *)
1438         let _ = debug_print (lazy ("MANGIO: " ^ string_of_int goalno)) in
1439         let orlist, fl = eat_head todo goalno fl orlist in
1440         let cache = 
1441           if size < minsize then 
1442             (debug_print (lazy ("NO CACHE: 2 (size <= minsize)"));cache)
1443           else 
1444           (* if the proof is closed we cache it *)
1445           if green_proof then cache_add_success cache key proof
1446           else (* cache_add_success cache key closed_proof *) 
1447             (debug_print (lazy ("NO CACHE: (no gree proof)"));cache)
1448         in
1449         cache, orlist, fl, true
1450       else
1451         let cache = 
1452           debug_print (lazy ("TENTATIVE CACHE: " ^ CicPp.ppterm gty));
1453           if size < minsize then 
1454             (debug_print (lazy ("NO CACHE: (size <= minsize)")); cache) else
1455           (* if the substituted goal and the proof are closed we cache it *)
1456           if is_a_green_cut gty then
1457             if green_proof then cache_add_success cache gty proof
1458             else (* cache_add_success cache gty closed_proof *) 
1459               (debug_print (lazy ("NO CACHE: (no green proof (gty))"));cache)
1460           else (*
1461             try
1462               let ty, _ =
1463                 CicTypeChecker.type_of_aux' ~subst:s 
1464                   m ctx closed_proof CicUniv.oblivion_ugraph
1465               in
1466               if is_a_green_cut ty then 
1467                 cache_add_success cache ty closed_proof
1468               else cache
1469             with
1470             | CicTypeChecker.TypeCheckerFailure _ ->*) 
1471           (debug_print (lazy ("NO CACHE: (no green gty )"));cache)
1472         in
1473         cache, orlist, fl, false
1474 ;;
1475 let close_failures (fl : fail list) (cache : cache) = 
1476   List.fold_left 
1477     (fun cache ((gno,depth,_),gty) -> 
1478       if CicUtil.is_meta_closed gty then
1479        ( debug_print (lazy ("FAIL: INDUCED: " ^ string_of_int gno));
1480          cache_add_failure cache gty depth) 
1481       else
1482          cache)
1483     cache fl
1484 ;;
1485 let put_in_subst subst metasenv  (goalno,_,_) canonical_ctx t ty =
1486   let entry = goalno, (canonical_ctx, t,ty) in
1487   assert_subst_are_disjoint subst [entry];
1488   let subst = entry :: subst in
1489   
1490   let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
1491
1492   subst, metasenv
1493 ;;
1494
1495 let mk_fake_proof metasenv subst (goalno,_,_) goalty context = 
1496   None,metasenv,subst ,(lazy (Cic.Meta(goalno,mk_irl context))),goalty, [] 
1497 ;;
1498
1499 let equational_case 
1500   tables cache depth fake_proof goalno goalty subst context 
1501     flags
1502 =
1503   let active,passive,bag = tables in
1504   let ppterm = ppterm context in
1505   let status = (fake_proof,goalno) in
1506     if flags.use_only_paramod then
1507       begin
1508         debug_print (lazy ("PARAMODULATION SU: " ^ 
1509                          string_of_int goalno ^ " " ^ ppterm goalty ));
1510         let goal_steps, saturation_steps, timeout =
1511           max_int,max_int,flags.timeout 
1512         in
1513         match
1514           Saturation.given_clause bag status active passive 
1515             goal_steps saturation_steps timeout
1516         with 
1517           | None, active, passive, bag -> 
1518               [], (active,passive,bag), cache, flags
1519           | Some(subst',(_,metasenv,_subst,proof,_, _),open_goals),active,
1520             passive,bag ->
1521               assert_subst_are_disjoint subst subst';
1522               let subst = subst@subst' in
1523               let open_goals = 
1524                 order_new_goals metasenv subst open_goals ppterm 
1525               in
1526               let open_goals = 
1527                 List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
1528               in
1529               incr candidate_no;
1530               [(!candidate_no,proof),metasenv,subst,open_goals], 
1531                 (active,passive,bag), cache, flags
1532       end
1533     else
1534       begin
1535         debug_print (lazy ("NARROWING DEL GOAL: " ^ 
1536                          string_of_int goalno ^ " " ^ ppterm goalty ));
1537         let goal_steps, saturation_steps, timeout =
1538           1,0,flags.timeout 
1539         in
1540         match
1541           Saturation.solve_narrowing bag status active passive goal_steps 
1542         with 
1543           | None, active, passive, bag -> 
1544               [], (active,passive,bag), cache, flags
1545           | Some(subst',(_,metasenv,_subst,proof,_, _),open_goals),active,
1546             passive,bag ->
1547               assert_subst_are_disjoint subst subst';
1548               let subst = subst@subst' in
1549               let open_goals = 
1550                 order_new_goals metasenv subst open_goals ppterm 
1551               in
1552               let open_goals = 
1553                 List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
1554               in
1555               incr candidate_no;
1556               [(!candidate_no,proof),metasenv,subst,open_goals], 
1557                 (active,passive,bag), cache, flags
1558       end
1559 (*
1560       begin
1561         let params = ([],["use_context","false"]) in
1562         let automation_cache = { 
1563               AutomationCache.tables = tables ;
1564               AutomationCache.univ = Universe.empty; }
1565         in
1566         try 
1567           let ((_,metasenv,subst,_,_,_),open_goals) =
1568
1569             solve_rewrite ~params ~automation_cache
1570               (fake_proof, goalno)
1571           in
1572           let proof = lazy (Cic.Meta (-1,[])) in
1573           [(!candidate_no,proof),metasenv,subst,[]],tables, cache, flags
1574         with ProofEngineTypes.Fail _ -> [], tables, cache, flags
1575 (*
1576         let res = Saturation.all_subsumed bag status active passive in
1577         let res' =
1578           List.map 
1579             (fun (subst',(_,metasenv,_subst,proof,_, _),open_goals) ->
1580                assert_subst_are_disjoint subst subst';
1581                let subst = subst@subst' in
1582                let open_goals = 
1583                  order_new_goals metasenv subst open_goals ppterm 
1584                in
1585                let open_goals = 
1586                  List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
1587                in
1588                incr candidate_no;
1589                  (!candidate_no,proof),metasenv,subst,open_goals)
1590             res 
1591           in
1592           res', (active,passive,bag), cache, flags 
1593 *)
1594       end
1595 *)
1596 ;;
1597
1598 let sort_new_elems = 
1599  List.sort (fun (_,_,_,l1) (_,_,_,l2) -> 
1600          let p1 = List.length (prop_only l1) in 
1601          let p2 = List.length (prop_only l2) in
1602          if p1 = p2 then List.length l1 - List.length l2 else p1-p2)
1603 ;;
1604
1605
1606 let try_candidate dbd
1607   goalty tables subst fake_proof goalno depth context cand 
1608 =
1609   let ppterm = ppterm context in
1610   try 
1611     let actives, passives, bag = tables in 
1612     let (_,metasenv,subst,_,_,_), open_goals =
1613        ProofEngineTypes.apply_tactic
1614         (PrimitiveTactics.apply_tac ~term:cand)
1615         (fake_proof,goalno) 
1616     in
1617     let tables = actives, passives, 
1618       Equality.push_maxmeta bag 
1619         (max (Equality.maxmeta bag) (CicMkImplicit.new_meta metasenv subst)) 
1620     in
1621     debug_print (lazy ("   OK: " ^ ppterm cand));
1622     let metasenv = CicRefine.pack_coercion_metasenv metasenv in
1623     let open_goals = order_new_goals metasenv subst open_goals ppterm in
1624     let open_goals = List.map (fun (x,sort) -> x,depth-1,sort) open_goals in
1625     incr candidate_no;
1626     Some ((!candidate_no,lazy cand),metasenv,subst,open_goals), tables 
1627   with 
1628     | ProofEngineTypes.Fail s -> None,tables
1629     | CicUnification.Uncertain s ->  None,tables
1630 ;;
1631
1632 let applicative_case dbd
1633   tables depth subst fake_proof goalno goalty metasenv context 
1634   universe cache flags
1635
1636   let goalty_aux = 
1637     match goalty with
1638     | Cic.Appl (hd::tl) -> 
1639         Cic.Appl (hd :: HExtlib.mk_list (Cic.Meta (0,[])) (List.length tl))
1640     | _ -> goalty
1641   in
1642   let candidates = 
1643     get_candidates flags.skip_trie_filtering universe cache goalty_aux
1644   in
1645   let tables, elems = 
1646     List.fold_left 
1647       (fun (tables,elems) cand ->
1648         match 
1649           try_candidate dbd goalty
1650             tables subst fake_proof goalno depth context cand
1651         with
1652         | None, tables -> tables, elems
1653         | Some x, tables -> tables, x::elems)
1654       (tables,[]) candidates
1655   in
1656   let elems = sort_new_elems elems in
1657   elems, tables, cache
1658 ;;
1659
1660 let try_smart_candidate dbd
1661   goalty tables subst fake_proof goalno depth context cand 
1662 =
1663   let ppterm = ppterm context in
1664   try
1665     let params = ([],[]) in
1666     let automation_cache = { 
1667           AutomationCache.tables = tables ;
1668           AutomationCache.univ = Universe.empty; }
1669     in
1670     debug_print (lazy ("candidato per " ^ string_of_int goalno 
1671       ^ ": " ^ CicPp.ppterm cand));
1672 (*
1673     let (_,metasenv,subst,_,_,_) = fake_proof in
1674     prerr_endline ("metasenv:\n" ^ CicMetaSubst.ppmetasenv [] metasenv);
1675     prerr_endline ("subst:\n" ^ CicMetaSubst.ppsubst ~metasenv subst);
1676 *)
1677     let ((_,metasenv,subst,_,_,_),open_goals) =
1678       apply_smart ~dbd ~term:cand ~params ~automation_cache
1679         (fake_proof, goalno)
1680     in
1681     let metasenv = CicRefine.pack_coercion_metasenv metasenv in
1682     let open_goals = order_new_goals metasenv subst open_goals ppterm in
1683     let open_goals = List.map (fun (x,sort) -> x,depth-1,sort) open_goals in
1684     incr candidate_no;
1685     Some ((!candidate_no,lazy cand),metasenv,subst,open_goals), tables 
1686   with 
1687   | ProofEngineTypes.Fail s -> None,tables
1688   | CicUnification.Uncertain s ->  None,tables
1689 ;;
1690
1691 let smart_applicative_case dbd
1692   tables depth subst fake_proof goalno goalty metasenv context signature
1693   universe cache flags
1694
1695   let goalty_aux = 
1696     match goalty with
1697     | Cic.Appl (hd::tl) -> 
1698         Cic.Appl (hd :: HExtlib.mk_list (Cic.Meta (0,[])) (List.length tl))
1699     | _ -> goalty
1700   in
1701   let smart_candidates = 
1702     get_candidates flags.skip_trie_filtering universe cache goalty_aux
1703   in
1704   let candidates = 
1705     get_candidates flags.skip_trie_filtering universe cache goalty
1706   in
1707   let smart_candidates = 
1708     List.filter
1709       (fun x -> not(List.mem x candidates)) smart_candidates
1710   in 
1711   let debug_msg =
1712     (lazy ("smart_candidates" ^ " = " ^ 
1713              (String.concat "\n" (List.map CicPp.ppterm smart_candidates)))) in
1714   debug_print debug_msg;
1715 (* we only filter the smart candidates since they could be too many *)
1716   let candidates = List.filter (only signature context metasenv) candidates in
1717   let smart_candidates = 
1718     List.filter (only signature context metasenv) smart_candidates 
1719   in
1720 (*
1721   let penalty cand depth = 
1722     if only signature context metasenv cand then depth else ((prerr_endline (
1723     "penalizzo " ^ CicPp.ppterm cand));depth -1)
1724   in
1725 *)
1726   let tables, elems = 
1727     List.fold_left 
1728       (fun (tables,elems) cand ->
1729         match 
1730           try_candidate dbd goalty
1731             tables subst fake_proof goalno depth context cand
1732         with
1733         | None, tables ->
1734             (* if normal application fails we try to be smart *)
1735             (match try_smart_candidate dbd goalty
1736                tables subst fake_proof goalno depth context cand
1737              with
1738                | None, tables -> tables, elems
1739                | Some x, tables -> tables, x::elems)
1740         | Some x, tables -> tables, x::elems)
1741       (tables,[]) candidates
1742   in
1743   let tables, smart_elems = 
1744       List.fold_left 
1745         (fun (tables,elems) cand ->
1746           match 
1747             try_smart_candidate dbd goalty
1748               tables subst fake_proof goalno depth context cand
1749           with
1750           | None, tables -> tables, elems
1751           | Some x, tables -> tables, x::elems)
1752         (tables,[]) smart_candidates
1753   in
1754   let elems = sort_new_elems (elems @ smart_elems) in
1755   elems, tables, cache
1756 ;;
1757
1758 let equational_and_applicative_case dbd
1759   signature universe flags m s g gty tables cache context 
1760 =
1761   let goalno, depth, sort = g in
1762   let fake_proof = mk_fake_proof m s g gty context in
1763   if is_equational_case gty flags then
1764     let elems,tables,cache, flags =
1765       equational_case tables cache
1766         depth fake_proof goalno gty s context flags 
1767     in
1768     let more_elems, tables, cache =
1769       if flags.use_only_paramod then
1770         [],tables, cache
1771       else
1772         applicative_case dbd
1773           tables depth s fake_proof goalno 
1774             gty m context universe cache flags
1775     in
1776       elems@more_elems, tables, cache, flags            
1777   else
1778     let elems, tables, cache =
1779       match LibraryObjects.eq_URI () with
1780       | Some _ ->
1781          smart_applicative_case dbd tables depth s fake_proof goalno 
1782            gty m context signature universe cache flags
1783       | None -> 
1784          applicative_case dbd tables depth s fake_proof goalno 
1785            gty m context universe cache flags
1786     in
1787       elems, tables, cache, flags  
1788 ;;
1789 let rec condition_for_hint i = function
1790   | [] -> false
1791   | S (_,_,(j,_),_):: tl -> j <> i (* && condition_for_hint i tl *)
1792   | _::tl -> condition_for_hint i tl
1793 ;;
1794 let remove_s_from_fl (id,_,_) (fl : fail list) =
1795   let rec aux = function
1796     | [] -> []
1797     | ((id1,_,_),_)::tl when id = id1 -> tl
1798     | hd::tl ->  hd :: aux tl
1799   in 
1800     aux fl
1801 ;;
1802
1803 let prunable_for_size flags s m todo =
1804   let rec aux b = function
1805     | (S _)::tl -> aux b tl
1806     | (D (_,_,T))::tl -> aux b tl
1807     | (D g)::tl -> 
1808         (match calculate_goal_ty g s m with
1809           | None -> aux b tl
1810           | Some (canonical_ctx, gty) -> 
1811             let gsize, _ = 
1812               Utils.weight_of_term 
1813                 ~consider_metas:false ~count_metas_occurrences:true gty in
1814             let newb = b || gsize > flags.maxgoalsizefactor in
1815             aux newb tl)
1816     | [] -> b
1817   in
1818     aux false todo
1819
1820 (*
1821 let prunable ty todo =
1822   let rec aux b = function
1823     | (S(_,k,_,_))::tl -> aux (b || Equality.meta_convertibility k ty) tl
1824     | (D (_,_,T))::tl -> aux b tl
1825     | D _::_ -> false
1826     | [] -> b
1827   in
1828     aux false todo
1829 ;;
1830 *)
1831
1832 let prunable menv subst ty todo =
1833   let rec aux = function
1834     | (S(_,k,_,_))::tl ->
1835          (match Equality.meta_convertibility_subst k ty menv with
1836           | None -> aux tl
1837           | Some variant -> 
1838                no_progress variant tl (* || aux tl*))
1839     | (D (_,_,T))::tl -> aux tl
1840     | _ -> false
1841   and no_progress variant = function
1842     | [] -> (*prerr_endline "++++++++++++++++++++++++ no_progress";*) true
1843     | D ((n,_,P) as g)::tl -> 
1844         (match calculate_goal_ty g subst menv with
1845            | None -> no_progress variant tl
1846            | Some (_, gty) -> 
1847                (match calculate_goal_ty g variant menv with
1848                   | None -> assert false
1849                   | Some (_, gty') ->
1850                       if gty = gty' then no_progress variant tl
1851 (* 
1852 (prerr_endline (string_of_int n);
1853  prerr_endline (CicPp.ppterm gty);
1854  prerr_endline (CicPp.ppterm gty');
1855  prerr_endline "---------- subst";
1856  prerr_endline (CicMetaSubst.ppsubst ~metasenv:menv subst);
1857  prerr_endline "---------- variant";
1858  prerr_endline (CicMetaSubst.ppsubst ~metasenv:menv variant);
1859  prerr_endline "---------- menv";
1860  prerr_endline (CicMetaSubst.ppmetasenv [] menv); 
1861                          no_progress variant tl) *)
1862                       else false))
1863     | _::tl -> no_progress variant tl
1864   in
1865     aux todo
1866
1867 ;;
1868 let condition_for_prune_hint prune (m, s, size, don, todo, fl) =
1869   let s = 
1870     HExtlib.filter_map (function S (_,_,(c,_),_) -> Some c | _ -> None) todo 
1871   in
1872   List.for_all (fun i -> List.for_all (fun j -> i<>j) prune) s
1873 ;;
1874 let filter_prune_hint c l =
1875   let prune = !prune_hint in
1876   prune_hint := []; (* possible race... *)
1877   if prune = [] then c,l
1878   else 
1879     cache_reset_underinspection c,      
1880     List.filter (condition_for_prune_hint prune) l
1881 ;;
1882
1883 let auto_main dbd tables context flags signature universe cache elems =
1884   auto_context := context;
1885   let rec aux tables flags cache (elems : status) =
1886     pp_status context elems;
1887 (* DEBUGGING CODE: uncomment these two lines to stop execution at each iteration
1888     auto_status := elems;
1889     check_pause ();
1890 *)
1891     let cache, elems = filter_prune_hint cache elems in
1892     match elems with
1893     | (m, s, size, don, todo, fl)::orlist when !hint <> None ->
1894         debug_print (lazy "skip");
1895         (match !hint with
1896         | Some i when condition_for_hint i todo ->
1897             aux tables flags cache orlist
1898         | _ ->
1899           hint := None;
1900           aux tables flags cache elems)
1901     | [] ->
1902         (* complete failure *)
1903         debug_print (lazy "give up");
1904         Gaveup (tables, cache)
1905     | (m, s, _, _, [],_)::orlist ->
1906         (* complete success *)
1907         debug_print (lazy "success");
1908         Proved (m, s, orlist, tables, cache)
1909     | (m, s, size, don, (D (_,_,T))::todo, fl)::orlist 
1910       when not flags.AutoTypes.do_types ->
1911         (* skip since not Prop, don't even check if closed by side-effect *)
1912         debug_print (lazy "skip existential goal");
1913         aux tables flags cache ((m, s, size, don, todo, fl)::orlist)
1914     | (m, s, size, don, (S(g, key, c,minsize) as op)::todo, fl)::orlist ->
1915         (* partial success, cache g and go on *)
1916         let cache, orlist, fl, sibling_pruned = 
1917           add_to_cache_and_del_from_orlist_if_green_cut 
1918             g s m cache key todo orlist fl context size minsize
1919         in
1920         debug_print (lazy (AutoCache.cache_print context cache));
1921         let fl = remove_s_from_fl g fl in
1922         let don = if sibling_pruned then don else op::don in
1923         aux tables flags cache ((m, s, size, don, todo, fl)::orlist)
1924     | (m, s, size, don, todo, fl)::orlist 
1925       when List.length(prop_only (d_goals todo)) > flags.maxwidth ->
1926         debug_print (lazy ("FAIL: WIDTH"));
1927         (* too many goals in and generated by last th *)
1928         let cache = close_failures fl cache in
1929         aux tables flags cache orlist
1930     | (m, s, size, don, todo, fl)::orlist when size > flags.maxsize ->
1931         debug_print 
1932           (lazy ("FAIL: SIZE: "^string_of_int size ^ 
1933             " > " ^ string_of_int flags.maxsize ));
1934         (* we already have a too large proof term *)
1935         let cache = close_failures fl cache in
1936         aux tables flags cache orlist
1937     | _ when Unix.gettimeofday () > flags.timeout ->
1938         (* timeout *)
1939         debug_print (lazy ("FAIL: TIMEOUT"));
1940         Gaveup (tables, cache)
1941     | (m, s, size, don, (D (gno,depth,_ as g))::todo, fl)::orlist as status ->
1942         (* attack g *) 
1943         debug_print (lazy "attack goal");
1944         match calculate_goal_ty g s m with
1945         | None -> 
1946             (* closed by side effect *)
1947             debug_print (lazy ("SUCCESS: SIDE EFFECT: " ^ string_of_int gno));
1948             aux tables flags cache ((m,s,size,don,todo, fl)::orlist)
1949         | Some (canonical_ctx, gty) ->
1950             let gsize, _ = 
1951               Utils.weight_of_term ~consider_metas:false ~count_metas_occurrences:true gty 
1952             in
1953             if gsize > flags.maxgoalsizefactor then
1954               (debug_print (lazy ("FAIL: SIZE: goal: "^string_of_int gsize));
1955                aux tables flags cache orlist)
1956             else if prunable_for_size flags s m todo then
1957                 (debug_print (lazy ("POTO at depth: "^(string_of_int depth)));
1958                  aux tables flags cache orlist)
1959             else
1960             (* still to be proved *)
1961             (debug_print (lazy ("EXAMINE: "^CicPp.ppterm gty));
1962             match cache_examine cache gty with
1963             | Failed_in d when d >= depth -> 
1964                 (* fail depth *)
1965                 debug_print (lazy ("FAIL: DEPTH (cache): "^string_of_int gno));
1966                 let cache = close_failures fl cache in
1967                 aux tables flags cache orlist
1968             | UnderInspection -> 
1969                 (* fail loop *)
1970                 debug_print (lazy ("FAIL: LOOP: " ^ string_of_int gno));
1971                 let cache = close_failures fl cache in
1972                 aux tables flags cache orlist
1973             | Succeded t -> 
1974                 debug_print (lazy ("SUCCESS: CACHE HIT: " ^ string_of_int gno));
1975                 let s, m = put_in_subst s m g canonical_ctx t gty in
1976                 aux tables flags cache ((m, s, size, don,todo, fl)::orlist)
1977             | Notfound 
1978             | Failed_in _ when depth > 0 -> 
1979                 ( (* more depth or is the first time we see the goal *)
1980                     if prunable m s gty todo then
1981                       (debug_print (lazy(
1982                          "FAIL: LOOP: one father is equal"));
1983                        aux tables flags cache orlist)
1984                     else
1985                     let cache = cache_add_underinspection cache gty depth in
1986                     auto_status := status;
1987                     check_pause ();
1988                     debug_print 
1989                       (lazy ("INSPECTING: " ^ 
1990                         string_of_int gno ^ "("^ string_of_int size ^ "): "^
1991                         CicPp.ppterm gty));
1992                     (* elems are possible computations for proving gty *)
1993                     let elems, tables, cache, flags =
1994                       equational_and_applicative_case dbd
1995                         signature universe flags m s g gty tables cache context
1996                     in
1997                     if elems = [] then
1998                       (* this goal has failed *)
1999                       let cache = close_failures ((g,gty)::fl) cache in
2000                       aux tables flags cache orlist
2001                     else
2002                       (* elems = (cand,m,s,gl) *)
2003                       let size_gl l = List.length 
2004                         (List.filter (function (_,_,P) -> true | _ -> false) l) 
2005                       in
2006                       let elems = 
2007                         let inj_gl gl = List.map (fun g -> D g) gl in
2008                         let rec map = function
2009                           | [] -> assert false
2010                           | (cand,m,s,gl)::[] ->
2011                               (* in the last one we add the failure *)
2012                               let todo = 
2013                                 inj_gl gl @ (S(g,gty,cand,size+1))::todo 
2014                               in
2015                               (* we are the last in OR, we fail on g and 
2016                                * also on all failures implied by g *)
2017                               (m,s, size + size_gl gl, don, todo, (g,gty)::fl)
2018                               :: orlist
2019                           | (cand,m,s,gl)::tl -> 
2020                               (* we add the S step after gl and before todo *)
2021                               let todo = 
2022                                 inj_gl gl @ (S(g,gty,cand,size+1))::todo 
2023                               in
2024                               (* since we are not the last in OR, we do not
2025                                * imply failures *)
2026                               (m,s, size + size_gl gl, don, todo, []) :: map tl
2027                         in
2028                           map elems
2029                       in
2030                         aux tables flags cache elems)
2031             | _ -> 
2032                 (* no more depth *)
2033                 debug_print (lazy ("FAIL: DEPTH: " ^ string_of_int gno));
2034                 let cache = close_failures fl cache in
2035                 aux tables flags cache orlist)
2036   in
2037     (aux tables flags cache elems : auto_result)
2038 ;;
2039     
2040
2041 let
2042   auto_all_solutions dbd tables universe cache context metasenv gl flags 
2043 =
2044   let signature =
2045     List.fold_left 
2046       (fun set g ->
2047          MetadataConstraints.UriManagerSet.union set 
2048              (MetadataQuery.signature_of metasenv g)
2049        )
2050       MetadataConstraints.UriManagerSet.empty gl 
2051   in
2052   let goals = order_new_goals metasenv [] gl CicPp.ppterm in
2053   let goals = 
2054     List.map 
2055       (fun (x,s) -> D (x,flags.maxdepth,s)) goals 
2056   in
2057   let elems = [metasenv,[],1,[],goals,[]] in
2058   let rec aux tables solutions cache elems flags =
2059     match auto_main dbd tables context flags signature universe cache elems with
2060     | Gaveup (tables,cache) ->
2061         solutions,cache, tables
2062     | Proved (metasenv,subst,others,tables,cache) -> 
2063         if Unix.gettimeofday () > flags.timeout then
2064           ((subst,metasenv)::solutions), cache, tables
2065         else
2066           aux tables ((subst,metasenv)::solutions) cache others flags
2067   in
2068   let rc = aux tables [] cache elems flags in
2069     match rc with
2070     | [],cache,tables -> [],cache,tables
2071     | solutions, cache,tables -> 
2072         let solutions = 
2073           HExtlib.filter_map
2074             (fun (subst,newmetasenv) ->
2075               let opened = 
2076                 ProofEngineHelpers.compare_metasenvs ~oldmetasenv:metasenv ~newmetasenv
2077               in
2078               if opened = [] then Some subst else None)
2079             solutions
2080         in
2081          solutions,cache,tables
2082 ;;
2083
2084 (******************* AUTO ***************)
2085
2086
2087 let auto dbd flags metasenv tables universe cache context metasenv gl =
2088   let initial_time = Unix.gettimeofday() in  
2089   let signature =
2090     List.fold_left 
2091       (fun set g ->
2092          MetadataConstraints.UriManagerSet.union set 
2093              (MetadataQuery.signature_of metasenv g)
2094        )
2095       MetadataConstraints.UriManagerSet.empty gl 
2096   in
2097   let goals = order_new_goals metasenv [] gl CicPp.ppterm in
2098   let goals = List.map (fun (x,s) -> D(x,flags.maxdepth,s)) goals in
2099   let elems = [metasenv,[],1,[],goals,[]] in
2100   match auto_main dbd tables context flags signature universe cache elems with
2101   | Proved (metasenv,subst,_, tables,cache) -> 
2102       debug_print(lazy
2103         ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
2104       Some (subst,metasenv), cache
2105   | Gaveup (tables,cache) -> 
2106       debug_print(lazy
2107         ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
2108       None,cache
2109 ;;
2110
2111 let auto_tac ~(dbd:HSql.dbd) ~params:(univ,params) ~automation_cache (proof, goal) =
2112   let flags = flags_of_params params () in
2113   let use_library = flags.use_library in
2114   let universe, tables, cache =
2115     init_cache_and_tables 
2116      ~dbd ~use_library ~use_context:(not flags.skip_context)
2117      automation_cache univ (proof, goal) 
2118   in
2119   let _,metasenv,subst,_,_, _ = proof in
2120   let _,context,goalty = CicUtil.lookup_meta goal metasenv in
2121   let signature = MetadataQuery.signature_of metasenv goal in
2122   let signature = 
2123     List.fold_left 
2124       (fun set t ->
2125          let ty, _ = 
2126            CicTypeChecker.type_of_aux' metasenv context t 
2127              CicUniv.oblivion_ugraph
2128          in
2129          MetadataConstraints.UriManagerSet.union set 
2130            (MetadataConstraints.constants_of ty)
2131        )
2132       signature univ
2133   in
2134   let tables,cache =
2135     if flags.close_more then
2136       close_more 
2137         tables context (proof, goal) 
2138           (auto_all_solutions dbd) signature universe cache 
2139     else tables,cache in
2140   let initial_time = Unix.gettimeofday() in
2141   let (_,oldmetasenv,_,_,_, _) = proof in
2142     hint := None;
2143   let elem = 
2144     metasenv,subst,1,[],[D (goal,flags.maxdepth,P)],[]
2145   in
2146   match auto_main dbd tables context flags signature universe cache [elem] with
2147     | Proved (metasenv,subst,_, tables,cache) -> 
2148         debug_print (lazy 
2149           ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
2150         let proof,metasenv =
2151         ProofEngineHelpers.subst_meta_and_metasenv_in_proof
2152           proof goal subst metasenv
2153         in
2154         let opened = 
2155           ProofEngineHelpers.compare_metasenvs ~oldmetasenv
2156             ~newmetasenv:metasenv
2157         in
2158           proof,opened
2159     | Gaveup (tables,cache) -> 
2160         debug_print
2161           (lazy ("TIME:"^
2162             string_of_float(Unix.gettimeofday()-.initial_time)));
2163         raise (ProofEngineTypes.Fail (lazy "Auto gave up"))
2164 ;;
2165
2166 let auto_tac ~dbd ~params ~automation_cache = 
2167   ProofEngineTypes.mk_tactic (auto_tac ~params ~dbd ~automation_cache);;
2168
2169 let pp_proofterm = Equality.pp_proofterm;;
2170
2171 let revision = "$Revision$";;
2172 let size_and_depth context metasenv t = 100, 100