]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/tactics/auto.ml
Constructors are closed with thier types when computing the signatur
[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 universe cache =
520   let proof, goalno = status in
521   let _, metasenv,subst,_,_, _ = proof in  
522   let signature = MetadataQuery.signature_of metasenv goalno in
523   let equations = 
524     retrieve_equations false signature universe cache context metasenv 
525   in
526   let eqs_and_types =
527     HExtlib.filter_map 
528       (fun t -> 
529          let ty,_ =
530            CicTypeChecker.type_of_aux' metasenv context t
531            CicUniv.oblivion_ugraph in
532            (* retrieve_equations could also return flexible terms *)
533            if is_an_equality ty then Some(t,ty) else None)
534       equations in
535   let tables, units, cache = 
536     build_equalities auto context metasenv subst tables universe cache eqs_and_types 
537   in
538   let active,passive,bag = tables in
539   let passive = Saturation.add_to_passive units passive in
540   let no = List.length units in
541   let active, passive, bag = 
542     Saturation.pump_actives context bag active passive (no+1) infinity
543   in 
544     (active,passive,bag), cache
545 ;;
546
547 let find_context_equalities dbd tables context proof (universe:Universe.universe) cache 
548 =
549   let module C = Cic in
550   let module S = CicSubstitution in
551   let module T = CicTypeChecker in
552   let _,metasenv,subst,_,_, _ = proof in
553   (* if use_auto is true, we try to close the hypothesis of equational
554     statements using auto; a naif, and probably wrong approach *)
555   let rec aux tables cache index = function
556     | [] -> tables, [], cache
557     | (Some (_, C.Decl (term)))::tl ->
558         debug_print
559           (lazy
560              (Printf.sprintf "Examining: %d (%s)" index (CicPp.ppterm term)));
561         let do_find tables context term =
562           match term with
563           | C.Prod (name, s, t) when is_an_equality t ->
564               (try 
565                 let term = S.lift index term in
566                 let saturated, cache, tables = 
567                   fill_hypothesis context metasenv subst term 
568                     tables universe cache default_auto false
569                 in
570                 let actives, passives, bag = tables in 
571                 let bag,eqs = 
572                   List.fold_left 
573                    (fun (bag,acc) (args,metasenv,newmetas,head) ->
574                      let bag, equality = 
575                        build_equality bag head args (Cic.Rel index) newmetas 
576                      in
577                      bag, equality::acc)
578                    (bag,[]) saturated
579                 in
580                 let tables = actives, passives, bag in
581                  tables, eqs, cache
582               with FillingFailure (cache,tables) ->
583                 tables, [], cache)
584           | C.Appl [C.MutInd (uri, _, _); ty; t1; t2]
585               when LibraryObjects.is_eq_URI uri ->
586               let term = S.lift index term in
587               let actives, passives, bag = tables in 
588               let bag, e = 
589                 build_equality bag term [] (Cic.Rel index) [] 
590               in
591               let tables = actives, passives, bag in
592               tables, [e], cache
593           | _ -> tables, [], cache
594         in 
595         let tables, eqs, cache = do_find tables context term in
596         let tables, rest, cache = aux tables cache (index+1) tl in
597         tables, List.map (fun x -> index,x) eqs @ rest, cache
598     | _::tl ->
599         aux tables cache (index+1) tl
600   in
601   let tables, il, cache = aux tables cache 1 context in
602   let indexes, equalities = List.split il in
603   tables, indexes, equalities, cache
604 ;;
605
606 (********** PARAMETERS PASSING ***************)
607
608 let bool params name default =
609     try 
610       let s = List.assoc name params in 
611       if s = "" || s = "1" || s = "true" || s = "yes" || s = "on" then true
612       else if s = "0" || s = "false" || s = "no" || s= "off" then false
613       else 
614         let msg = "Unrecognized value for parameter "^name^"\n" in
615         let msg = msg^"Accepted values are 1,true,yes,on and 0,false,no,off" in
616         raise (ProofEngineTypes.Fail (lazy msg))
617     with Not_found -> default
618 ;; 
619
620 let string params name default =
621     try List.assoc name params with
622     | Not_found -> default
623 ;; 
624
625 let int params name default =
626     try int_of_string (List.assoc name params) with
627     | Not_found -> default
628     | Failure _ -> 
629         raise (ProofEngineTypes.Fail (lazy (name ^ " must be an integer")))
630 ;;  
631
632 let flags_of_params params ?(for_applyS=false) () =
633  let int = int params in
634  let bool = bool params in
635  let close_more = bool "close_more" false in
636  let use_paramod = bool "use_paramod" true in
637  let skip_trie_filtering = bool "skip_trie_filtering" false in
638  let skip_context = bool "skip_context" false in
639  let use_only_paramod =
640   if for_applyS then true else bool "paramodulation" false in
641  let use_library = bool "library"  
642    ((AutoTypes.default_flags()).AutoTypes.use_library) in
643  let depth = int "depth" ((AutoTypes.default_flags()).AutoTypes.maxdepth) in
644  let width = int "width" ((AutoTypes.default_flags()).AutoTypes.maxwidth) in
645  let size = int "size" ((AutoTypes.default_flags()).AutoTypes.maxsize) in
646  let gsize = int "gsize" ((AutoTypes.default_flags()).AutoTypes.maxgoalsizefactor) in
647  let do_type = bool "type" false in
648  let timeout = int "timeout" 0 in
649   { AutoTypes.maxdepth = 
650       if use_only_paramod then 2 else depth;
651     AutoTypes.maxwidth = width;
652     AutoTypes.maxsize = size;
653     AutoTypes.timeout = 
654       if timeout = 0 then
655        if for_applyS then Unix.gettimeofday () +. 30.0
656        else
657          infinity
658       else
659        Unix.gettimeofday() +. (float_of_int timeout);
660     AutoTypes.use_library = use_library; 
661     AutoTypes.use_paramod = use_paramod;
662     AutoTypes.use_only_paramod = use_only_paramod;
663     AutoTypes.close_more = close_more;
664     AutoTypes.dont_cache_failures = false;
665     AutoTypes.maxgoalsizefactor = gsize;
666     AutoTypes.do_types = do_type;
667     AutoTypes.skip_trie_filtering = skip_trie_filtering;
668     AutoTypes.skip_context = skip_context;
669   }
670
671
672 let eq_of_goal = function
673   | Cic.Appl [Cic.MutInd(uri,0,_);_;_;_] when LibraryObjects.is_eq_URI uri ->
674       uri
675   | _ -> raise (ProofEngineTypes.Fail (lazy ("The goal is not an equality ")))
676 ;;
677
678 (* performs steps of rewrite with the universe, obtaining if possible 
679  * a trivial goal *)
680 let solve_rewrite ~automation_cache ~params:(univ,params) (proof,goal)= 
681   let steps = int_of_string (string params "steps" "4") in 
682   let use_context = bool params "use_context" true in 
683   let universe, tables, cache =
684    init_cache_and_tables ~use_library:false ~use_context
685      automation_cache univ (proof,goal) 
686   in
687   let actives, passives, bag = tables in 
688   let pa,metasenv,subst,pb,pc,pd = proof in
689   let _,context,ty = CicUtil.lookup_meta goal metasenv in
690   let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
691   let context = CicMetaSubst.apply_subst_context subst context in
692   let ty = CicMetaSubst.apply_subst subst ty in
693   let eq_uri = eq_of_goal ty in
694   let initgoal = [], metasenv, ty in
695   let table = 
696     let equalities = (Saturation.list_of_passive passives) in
697     List.fold_left (fun tbl eq -> Indexing.index tbl eq) (snd actives) equalities
698   in
699   let env = metasenv,context,CicUniv.oblivion_ugraph in
700   debug_print (lazy ("demod to solve: " ^ CicPp.ppterm ty));
701   match Indexing.solve_demodulating bag env table initgoal steps with 
702   | Some (bag, gproof, metasenv, sub_subst, proof) ->
703       let subst_candidates,extra_infos = 
704         List.split 
705           (HExtlib.filter_map 
706              (fun (i,c,_) -> 
707                 if i <> goal && c = context then Some (i,(c,ty)) else None) 
708              metasenv)
709       in
710       let proofterm,proto_subst = 
711         let proof = Equality.add_subst sub_subst proof in
712         Equality.build_goal_proof 
713           bag eq_uri gproof proof ty subst_candidates context metasenv
714       in
715       let proofterm = Subst.apply_subst sub_subst proofterm in
716       let extrasubst = 
717         HExtlib.filter_map
718           (fun (i,((c,ty),t)) -> 
719              match t with
720              | Cic.Meta (j,_) when i=j -> None
721              | _ -> Some (i,(c,t,ty)))
722           (List.combine subst_candidates 
723             (List.combine extra_infos proto_subst))
724       in
725       let subst = subst @ extrasubst in
726       let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
727       let proofterm, _, metasenv,subst, _ =
728         CicRefine.type_of metasenv subst context proofterm
729           CicUniv.oblivion_ugraph
730       in
731       let status = (pa,metasenv,subst,pb,pc,pd), goal in
732       ProofEngineTypes.apply_tactic 
733         (PrimitiveTactics.apply_tac ~term:proofterm) status
734   | None -> 
735       raise 
736         (ProofEngineTypes.Fail (lazy 
737           ("Unable to solve with " ^ string_of_int steps ^ " demodulations")))
738 ;;
739
740 (* Demodulate thorem *)
741 let open_type ty bo =
742   let rec open_type_aux context ty k args =
743     match ty with 
744       | Cic.Prod (n,s,t) ->
745           let n' = 
746             FreshNamesGenerator.mk_fresh_name [] context n ~typ:s ~subst:[] in
747           let entry = match n' with
748             | Cic.Name _    -> Some (n',(Cic.Decl s))
749             | Cic.Anonymous -> None
750           in
751             open_type_aux (entry::context) t (k+1) ((Cic.Rel k)::args)
752       | Cic.LetIn (n,s,sty,t) ->
753           let entry = Some (n,(Cic.Def (s,sty)))
754           in
755             open_type_aux (entry::context) t (k+1) args
756       | _  -> context, ty, args
757   in
758   let context, ty, args = open_type_aux [] ty 1 [] in
759   match args with
760     | [] -> context, ty, bo
761     | _ -> context, ty, Cic.Appl (bo::args)
762 ;; 
763
764 let rec close_type bo ty context =
765   match context with 
766     | [] -> assert_proof_is_valid bo [] [] ty; (bo,ty)
767     | Some (n,(Cic.Decl s))::tl ->
768         close_type (Cic.Lambda (n,s,bo)) (Cic.Prod (n,s,ty)) tl
769     | Some (n,(Cic.Def (s,sty)))::tl ->
770         close_type (Cic.LetIn (n,s,sty,bo)) (Cic.LetIn (n,s,sty,ty)) tl
771     | _ -> assert false
772 ;; 
773
774 let is_subsumed univ context ty =
775   let candidates = Universe.get_candidates univ ty in
776     List.fold_left 
777       (fun res cand ->
778          match res with
779            | Some found -> Some found
780            | None -> 
781                try 
782                  let mk_irl = 
783                    CicMkImplicit.identity_relocation_list_for_metavariable in
784                  let metasenv = [(0,context,ty)] in
785                  let fake_proof = 
786                    None,metasenv,[] , (lazy (Cic.Meta(0,mk_irl context))),ty,[]
787                  in
788                  let (_,metasenv,subst,_,_,_), open_goals =
789                    ProofEngineTypes.apply_tactic 
790                      (PrimitiveTactics.apply_tac ~term:cand) 
791                      (fake_proof,0)
792                  in
793                  let prop_goals, other = 
794                    split_goals_in_prop metasenv subst open_goals 
795                  in
796                   if prop_goals = [] then Some cand else None
797                with 
798                  | ProofEngineTypes.Fail s -> None
799                  | CicUnification.Uncertain s ->  None
800       ) None candidates
801 ;;
802
803 let demodulate_theorem ~automation_cache uri =
804   let eq_uri = 
805     match LibraryObjects.eq_URI () with
806       | Some (uri) -> uri
807       | None -> raise (ProofEngineTypes.Fail (lazy "equality not declared")) in
808   let obj,_ = CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
809   in
810   let context,ty,bo =
811     match obj with 
812       | Cic.Constant(n, _, ty ,_, _) -> open_type ty (Cic.Const(uri,[]))
813       | _ -> raise (ProofEngineTypes.Fail (lazy "not a theorem"))
814   in
815   if CicUtil.is_closed ty then 
816     raise (ProofEngineTypes.Fail (lazy ("closed term: dangerous reduction")));
817   let initgoal = [], [], ty in
818   (* compute the signature *)
819   let signature = 
820     let ty_set = MetadataConstraints.constants_of ty in
821     let hyp_set = MetadataQuery.signature_of_hypothesis context [] in
822     let set = MetadataConstraints.UriManagerSet.union ty_set hyp_set in
823       MetadataQuery.close_with_types set [] context 
824   in
825   (* retrieve equations from the universe universe *)
826   (* XXX automation_cache *)
827   let universe = automation_cache.AutomationCache.univ in
828   let equations = 
829     retrieve_equations true signature universe AutoCache.cache_empty context []
830   in
831   debug_print 
832     (lazy ("ho trovato equazioni n. "^(string_of_int (List.length equations))));
833   let eqs_and_types =
834     HExtlib.filter_map 
835       (fun t -> 
836          let ty,_ =
837            CicTypeChecker.type_of_aux' [] context t CicUniv.oblivion_ugraph
838          in
839          (* retrieve_equations could also return flexible terms *)
840          if is_an_equality ty then Some(t,ty) 
841          else
842            try
843              let ty' = unfold context ty in
844              if is_an_equality ty' then Some(t,ty') else None
845            with ProofEngineTypes.Fail _ -> None) 
846       equations
847   in
848   let bag = Equality.mk_equality_bag () in
849
850   let bag, units, _, newmeta = 
851     partition_unit_equalities context [] (CicMkImplicit.new_meta [] []) bag eqs_and_types 
852   in
853   let table =
854     List.fold_left 
855       (fun tbl eq -> Indexing.index tbl eq) 
856       Indexing.empty units
857   in 
858   let changed,(newproof,newmetasenv, newty) =
859     Indexing.demod bag
860       ([],context,CicUniv.oblivion_ugraph) table initgoal in
861   if changed then
862     begin
863       let oldproof = Equality.Exact bo in
864       let proofterm,_ = 
865         Equality.build_goal_proof (~contextualize:false) (~forward:true) bag
866           eq_uri newproof oldproof ty [] context newmetasenv
867       in
868       if newmetasenv <> [] then 
869         raise (ProofEngineTypes.Fail (lazy ("metasenv not empty")))
870       else
871         begin
872           assert_proof_is_valid proofterm newmetasenv context newty;
873           match is_subsumed universe context newty with
874             | Some t -> raise 
875                 (ProofEngineTypes.Fail (lazy ("subsumed by " ^ CicPp.ppterm t)))
876             | None -> close_type proofterm newty context 
877         end
878     end
879   else (* if newty = ty then *)
880     raise (ProofEngineTypes.Fail (lazy "no progress"))
881   (*else ProofEngineTypes.apply_tactic 
882     (ReductionTactics.simpl_tac
883       ~pattern:(ProofEngineTypes.conclusion_pattern None)) initialstatus*)
884 ;;      
885
886
887 (* NEW DEMODULATE *)
888 let demodulate ~dbd ~automation_cache ~params:(univ, params) (proof,goal)= 
889   let universe, tables, cache =
890      init_cache_and_tables 
891        ~dbd ~use_library:false ~use_context:true
892        automation_cache univ (proof,goal) 
893   in
894   let eq_uri = 
895     match LibraryObjects.eq_URI () with
896       | Some (uri) -> uri
897       | None -> raise (ProofEngineTypes.Fail (lazy "equality not declared")) in
898   let active, passive, bag = tables in
899   let curi,metasenv,subst,pbo,pty, attrs = proof in
900   let metano,context,ty = CicUtil.lookup_meta goal metasenv in
901   let irl = CicMkImplicit.identity_relocation_list_for_metavariable context in
902   let initgoal = [], metasenv, ty in
903   let equalities = (Saturation.list_of_passive passive) in
904   (* we demodulate using both actives passives *)
905   let env = metasenv,context,CicUniv.empty_ugraph in
906   debug_print (lazy ("PASSIVES:" ^ string_of_int(List.length equalities)));
907   List.iter (fun e -> debug_print (lazy (Equality.string_of_equality ~env e)))
908     equalities;
909   let table = 
910     List.fold_left 
911       (fun tbl eq -> Indexing.index tbl eq) 
912       (snd active) equalities
913   in
914   let changed,(newproof,newmetasenv, newty) =
915     (* Indexing.demodulation_goal bag *)
916       Indexing.demod bag
917       (metasenv,context,CicUniv.oblivion_ugraph) table initgoal 
918   in
919   if changed then
920     begin
921       let maxm = CicMkImplicit.new_meta metasenv subst in
922       let opengoal = Equality.Exact (Cic.Meta(maxm,irl)) in
923       let subst_candidates = List.map (fun (i,_,_) -> i) metasenv in
924       let subst_candidates = List.filter (fun x-> x <> goal) subst_candidates in
925       let proofterm, proto_subst = 
926         Equality.build_goal_proof (~contextualize:false) bag
927           eq_uri newproof opengoal ty subst_candidates context metasenv
928       in
929       (* XXX understan what to do with proto subst *)
930       let metasenv = (maxm,context,newty)::metasenv in
931       let proofterm, _, metasenv, subst, _ =
932         CicRefine.type_of metasenv subst context proofterm
933           CicUniv.oblivion_ugraph
934       in
935       let extended_status = (curi,metasenv,subst,pbo,pty, attrs),goal in
936       let proof,gl = 
937         ProofEngineTypes.apply_tactic 
938           (PrimitiveTactics.apply_tac ~term:proofterm) extended_status
939       in
940         proof,maxm::gl
941     end
942   else 
943     raise (ProofEngineTypes.Fail (lazy "no progress"))
944 ;;
945
946 let demodulate_tac ~dbd ~params:(_,flags as params) ~automation_cache =
947  ProofEngineTypes.mk_tactic 
948   (fun status -> 
949     let all = bool flags "all" false in
950     if all then
951       solve_rewrite ~params ~automation_cache status
952     else
953       demodulate ~dbd ~params ~automation_cache status)
954 ;;
955 (***************** applyS *******************)
956
957 let apply_smart_aux 
958  dbd automation_cache params proof goal newmeta' metasenv' subst
959   context term' ty termty goal_arity 
960
961  let consthead,newmetasenv,arguments,_ =
962    TermUtil.saturate_term newmeta' metasenv' context termty goal_arity in
963  let term'' = 
964    match arguments with 
965    | [] -> term' 
966    | _ -> Cic.Appl (term'::arguments) 
967  in
968  let consthead = 
969    let rec aux t = function
970      | [] -> 
971         let t = CicReduction.normalize ~delta:false context t in
972         (match t, ty with
973         | Cic.Appl (hd1::_), Cic.Appl (hd2::_) when hd1 <> hd2 ->
974              let t = ProofEngineReduction.unfold context t in
975              (match t with
976              | Cic.Appl (hd1'::_) when hd1' = hd2 -> t
977              | _ -> raise (ProofEngineTypes.Fail (lazy "incompatible head")))
978         | _ -> t)
979      | arg :: tl -> 
980          match CicReduction.whd context t with
981          | Cic.Prod (_,_,tgt) -> 
982              aux (CicSubstitution.subst arg tgt) tl
983          | _ -> assert false
984    in
985     aux termty arguments
986  in
987  let goal_for_paramod =
988   match LibraryObjects.eq_URI () with
989   | Some uri -> 
990       Cic.Appl [Cic.MutInd (uri,0,[]); Cic.Implicit (Some `Type); consthead; ty]
991   | None -> raise (ProofEngineTypes.Fail (lazy "No equality defined"))
992  in
993  try 
994    let goal_for_paramod, _, newmetasenv, subst, _ = 
995      CicRefine.type_of newmetasenv subst context goal_for_paramod 
996        CicUniv.oblivion_ugraph
997    in
998    let newmeta = CicMkImplicit.new_meta newmetasenv subst in
999    let metasenv_for_paramod = (newmeta,context,goal_for_paramod)::newmetasenv in
1000    let proof'' = 
1001      let uri,_,_,p,ty, attrs = proof in 
1002      uri,metasenv_for_paramod,subst,p,ty, attrs 
1003    in
1004    let irl = CicMkImplicit.identity_relocation_list_for_metavariable context in
1005 (*
1006    prerr_endline ("------ prima di rewrite su ------ " ^ string_of_int goal);
1007    prerr_endline ("menv:\n"^CicMetaSubst.ppmetasenv [] metasenv_for_paramod);
1008    prerr_endline ("subst:\n"^CicMetaSubst.ppsubst
1009      ~metasenv:(metasenv_for_paramod)
1010      subst);
1011 *)
1012
1013    let (proof''',goals) =
1014       ProofEngineTypes.apply_tactic 
1015         (EqualityTactics.rewrite_tac ~direction:`RightToLeft
1016         ~pattern:(ProofEngineTypes.conclusion_pattern None)
1017         (Cic.Meta(newmeta,irl)) []) (proof'',goal)
1018    in
1019    let goal = match goals with [g] -> g | _ -> assert false in
1020    let  proof'''', _  =
1021      ProofEngineTypes.apply_tactic 
1022        (PrimitiveTactics.apply_tac term'')
1023        (proof''',goal) 
1024    in
1025
1026
1027    let (_,m,_,_,_,_ as p) = 
1028         let pu,metasenv,subst,proof,px,py = proof'''' in
1029         let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
1030         let proof'''' = pu,metasenv,subst,proof,px,py in
1031         let univ, params = params in
1032         let use_context = bool params "use_context" true in 
1033         let universe, (active,passive,bag), cache =
1034          init_cache_and_tables ~use_library:false ~use_context
1035            automation_cache univ (proof'''',newmeta)
1036         in
1037         match
1038           Saturation.solve_narrowing bag (proof'''',newmeta) active passive 
1039             1 (*0 infinity*)
1040         with 
1041           | None, active, passive, bag -> 
1042               raise (ProofEngineTypes.Fail (lazy ("paramod fails")))
1043           | Some(subst',(pu,metasenv,_,proof,px, py),open_goals),active,
1044             passive,bag ->
1045               assert_subst_are_disjoint subst subst';
1046               let subst = subst@subst' in
1047               pu,metasenv,subst,proof,px,py
1048    in
1049
1050 (*
1051    let (_,m,_,_,_,_ as p),_ = 
1052       solve_rewrite ~params ~automation_cache (proof'''',newmeta)
1053    in
1054 *)
1055
1056    let open_goals = 
1057      ProofEngineHelpers.compare_metasenvs ~oldmetasenv:metasenv' ~newmetasenv:m
1058    in
1059    p, open_goals 
1060  with
1061    CicRefine.RefineFailure msg -> 
1062      raise (ProofEngineTypes.Fail msg)
1063 ;;
1064
1065 let apply_smart 
1066   ~dbd ~term ~automation_cache ~params (proof, goal) 
1067 =
1068  let module T = CicTypeChecker in
1069  let module R = CicReduction in
1070  let module C = Cic in
1071   let (_,metasenv,subst,_,_, _) = proof in
1072   let metano,context,ty = CicUtil.lookup_meta goal metasenv in
1073   let newmeta = CicMkImplicit.new_meta metasenv subst in
1074    let exp_named_subst_diff,newmeta',newmetasenvfragment,term' =
1075     match term with
1076        C.Var (uri,exp_named_subst) ->
1077         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1078          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1079           exp_named_subst
1080         in
1081          exp_named_subst_diff,newmeta',newmetasenvfragment,
1082           C.Var (uri,exp_named_subst')
1083      | C.Const (uri,exp_named_subst) ->
1084         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1085          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1086           exp_named_subst
1087         in
1088          exp_named_subst_diff,newmeta',newmetasenvfragment,
1089           C.Const (uri,exp_named_subst')
1090      | C.MutInd (uri,tyno,exp_named_subst) ->
1091         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1092          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1093           exp_named_subst
1094         in
1095          exp_named_subst_diff,newmeta',newmetasenvfragment,
1096           C.MutInd (uri,tyno,exp_named_subst')
1097      | C.MutConstruct (uri,tyno,consno,exp_named_subst) ->
1098         let newmeta',newmetasenvfragment,exp_named_subst',exp_named_subst_diff =
1099          PrimitiveTactics.generalize_exp_named_subst_with_fresh_metas context newmeta uri
1100           exp_named_subst
1101         in
1102          exp_named_subst_diff,newmeta',newmetasenvfragment,
1103           C.MutConstruct (uri,tyno,consno,exp_named_subst')
1104      | _ -> [],newmeta,[],term
1105    in
1106    let metasenv' = metasenv@newmetasenvfragment in
1107    let termty,_ = 
1108      CicTypeChecker.type_of_aux' 
1109       metasenv' ~subst context term' CicUniv.oblivion_ugraph
1110    in
1111    let termty = CicSubstitution.subst_vars exp_named_subst_diff termty in
1112    let goal_arity = 
1113      let rec count_prods context ty =
1114       match CicReduction.whd ~subst context ty with
1115       | Cic.Prod (n,s,t) -> 1 + count_prods (Some (n,Cic.Decl s)::context) t
1116       | _ -> 0
1117      in
1118        count_prods context ty
1119    in
1120     apply_smart_aux dbd automation_cache params proof goal 
1121      newmeta' metasenv' subst context term' ty termty goal_arity
1122 ;;
1123
1124 let applyS_tac ~dbd ~term ~params ~automation_cache =
1125  ProofEngineTypes.mk_tactic
1126   (fun status ->
1127     try 
1128       apply_smart ~dbd ~term ~params ~automation_cache status
1129     with 
1130     | CicUnification.UnificationFailure msg
1131     | CicTypeChecker.TypeCheckerFailure msg ->
1132         raise (ProofEngineTypes.Fail msg))
1133 ;;
1134
1135
1136 (****************** AUTO ********************)
1137
1138 let calculate_timeout flags = 
1139     if flags.timeout = 0. then 
1140       (debug_print (lazy "AUTO WITH NO TIMEOUT");
1141        {flags with timeout = infinity})
1142     else 
1143       flags 
1144 ;;
1145 let is_equational_case goalty flags =
1146   let ensure_equational t = 
1147     if is_an_equational_goal t then true 
1148     else false
1149   in
1150   (flags.use_paramod && is_an_equational_goal goalty) || 
1151   (flags.use_only_paramod && ensure_equational goalty)
1152 ;;
1153
1154 type menv = Cic.metasenv
1155 type subst = Cic.substitution
1156 type goal = ProofEngineTypes.goal * int * AutoTypes.sort
1157 let candidate_no = ref 0;;
1158 type candidate = int * Cic.term Lazy.t
1159 type cache = AutoCache.cache
1160
1161 type fail = 
1162   (* the goal (mainly for depth) and key of the goal *)
1163   goal * AutoCache.cache_key
1164 type op = 
1165   (* goal has to be proved *)
1166   | D of goal 
1167   (* goal has to be cached as a success obtained using candidate as the first
1168    * step *)
1169   | S of goal * AutoCache.cache_key * candidate * int 
1170 type elem = 
1171   (* menv, subst, size, operations done (only S), operations to do, failures to cache if any op fails *)
1172   menv * subst * int * op list * op list * fail list 
1173 type status = 
1174   (* list of computations that may lead to the solution: all op list will
1175    * end with the same (S(g,_)) *)
1176   elem list
1177 type auto_result = 
1178   (* menv, subst, alternatives, tables, cache *)
1179   | Proved of menv * subst * elem list * AutomationCache.tables * cache 
1180   | Gaveup of AutomationCache.tables * cache 
1181
1182
1183 (* the status exported to the external observer *)  
1184 type auto_status = 
1185   (* context, (goal,candidate) list, and_list, history *)
1186   Cic.context * (int * Cic.term * bool * int * (int * Cic.term Lazy.t) list) list * 
1187   (int * Cic.term * int) list * Cic.term Lazy.t list
1188
1189 let d_prefix l =
1190   let rec aux acc = function
1191     | (D g)::tl -> aux (acc@[g]) tl
1192     | _ -> acc
1193   in
1194     aux [] l
1195 ;;
1196 let prop_only l =
1197   List.filter (function (_,_,P) -> true | _ -> false) l
1198 ;;
1199
1200 let d_goals l =
1201   let rec aux acc = function
1202     | (D g)::tl -> aux (acc@[g]) tl
1203     | (S _)::tl -> aux acc tl
1204     | [] -> acc
1205   in
1206     aux [] l
1207 ;;
1208
1209 let calculate_goal_ty (goalno,_,_) s m = 
1210   try
1211     let _,cc,goalty = CicUtil.lookup_meta goalno m in
1212     (* XXX applicare la subst al contesto? *)
1213     Some (cc, CicMetaSubst.apply_subst s goalty)
1214   with CicUtil.Meta_not_found i when i = goalno -> None
1215 ;;
1216
1217 let calculate_closed_goal_ty (goalno,_,_) s = 
1218   try
1219     let cc,_,goalty = List.assoc goalno s in
1220     (* XXX applicare la subst al contesto? *)
1221     Some (cc, CicMetaSubst.apply_subst s goalty)
1222   with Not_found -> 
1223     None
1224 ;;
1225
1226 let pp_status ctx status = 
1227   if debug then 
1228   let names = Utils.names_of_context ctx in
1229   let pp x = 
1230     let x = 
1231       ProofEngineReduction.replace 
1232         ~equality:(fun a b -> match b with Cic.Meta _ -> true | _ -> false) 
1233           ~what:[Cic.Rel 1] ~with_what:[Cic.Implicit None] ~where:x
1234     in
1235     CicPp.pp x names
1236   in
1237   let string_of_do m s (gi,_,_ as g) d =
1238     match calculate_goal_ty g s m with
1239     | Some (_,gty) -> Printf.sprintf "D(%d, %s, %d)" gi (pp gty) d
1240     | None -> Printf.sprintf "D(%d, _, %d)" gi d
1241   in
1242   let string_of_s m su k (ci,ct) gi =
1243     Printf.sprintf "S(%d, %s, %s, %d)" gi (pp k) (pp (Lazy.force ct)) ci
1244   in
1245   let string_of_ol m su l =
1246     String.concat " | " 
1247       (List.map 
1248         (function 
1249           | D (g,d,s) -> string_of_do m su (g,d,s) d 
1250           | S ((gi,_,_),k,c,_) -> string_of_s m su k c gi) 
1251         l)
1252   in
1253   let string_of_fl m s fl = 
1254     String.concat " | " 
1255       (List.map (fun ((i,_,_),ty) -> 
1256          Printf.sprintf "(%d, %s)" i (pp ty)) fl)
1257   in
1258   let rec aux = function
1259     | [] -> ()
1260     | (m,s,_,_,ol,fl)::tl ->
1261         Printf.eprintf "< [%s] ;;; [%s]>\n" 
1262           (string_of_ol m s ol) (string_of_fl m s fl);
1263         aux tl
1264   in
1265     Printf.eprintf "-------------------------- status -------------------\n";
1266     aux status;
1267     Printf.eprintf "-----------------------------------------------------\n";
1268 ;;
1269   
1270 let auto_status = ref [] ;;
1271 let auto_context = ref [];;
1272 let in_pause = ref false;;
1273 let pause b = in_pause := b;;
1274 let cond = Condition.create ();;
1275 let mutex = Mutex.create ();;
1276 let hint = ref None;;
1277 let prune_hint = ref [];;
1278
1279 let step _ = Condition.signal cond;;
1280 let give_hint n = hint := Some n;;
1281 let give_prune_hint hint =
1282   prune_hint := hint :: !prune_hint
1283 ;;
1284
1285 let check_pause _ =
1286   if !in_pause then
1287     begin
1288       Mutex.lock mutex;
1289       Condition.wait cond mutex;
1290       Mutex.unlock mutex
1291     end
1292 ;;
1293
1294 let get_auto_status _ = 
1295   let status = !auto_status in
1296   let and_list,elems,last = 
1297     match status with
1298     | [] -> [],[],[]
1299     | (m,s,_,don,gl,fail)::tl ->
1300         let and_list = 
1301           HExtlib.filter_map 
1302             (fun (id,d,_ as g) -> 
1303               match calculate_goal_ty g s m with
1304               | Some (_,x) -> Some (id,x,d) | None -> None)
1305             (d_goals gl)
1306         in
1307         let rows = 
1308           (* these are the S goalsin the or list *)
1309           let orlist = 
1310             List.map
1311               (fun (m,s,_,don,gl,fail) -> 
1312                 HExtlib.filter_map
1313                   (function S (g,k,c,_) -> Some (g,k,c) | _ -> None) 
1314                   (List.rev don @ gl))
1315               status
1316           in
1317           (* this function eats id from a list l::[id,x] returning x, l *)
1318           let eat_tail_if_eq id l = 
1319             let rec aux (s, l) = function
1320               | [] -> s, l
1321               | ((id1,_,_),k1,c)::tl when id = id1 ->
1322                   (match s with
1323                   | None -> aux (Some c,l) tl
1324                   | Some _ -> assert false)
1325               | ((id1,_,_),k1,c as e)::tl -> aux (s, e::l) tl
1326             in
1327             let c, l = aux (None, []) l in
1328             c, List.rev l
1329           in
1330           let eat_in_parallel id l =
1331             let rec aux (b,eaten, new_l as acc) l =
1332               match l with
1333               | [] -> acc
1334               | l::tl ->
1335                   match eat_tail_if_eq id l with
1336                   | None, l -> aux (b@[false], eaten, new_l@[l]) tl
1337                   | Some t,l -> aux (b@[true],eaten@[t], new_l@[l]) tl
1338             in
1339             aux ([],[],[]) l
1340           in
1341           let rec eat_all rows l =
1342             match l with
1343             | [] -> rows
1344             | elem::or_list ->
1345                 match List.rev elem with
1346                 | ((to_eat,depth,_),k,_)::next_lunch ->
1347                     let b, eaten, l = eat_in_parallel to_eat l in
1348                     let eaten = HExtlib.list_uniq eaten in
1349                     let eaten = List.rev eaten in
1350                     let b = true (* List.hd (List.rev b) *) in
1351                     let rows = rows @ [to_eat,k,b,depth,eaten] in
1352                     eat_all rows l
1353                 | [] -> eat_all rows or_list
1354           in
1355           eat_all [] (List.rev orlist)
1356         in
1357         let history = 
1358           HExtlib.filter_map
1359             (function (S (_,_,(_,c),_)) -> Some c | _ -> None) 
1360             gl 
1361         in
1362 (*         let rows = List.filter (fun (_,l) -> l <> []) rows in *)
1363         and_list, rows, history
1364   in
1365   !auto_context, elems, and_list, last
1366 ;;
1367
1368 (* Works if there is no dependency over proofs *)
1369 let is_a_green_cut goalty =
1370   CicUtil.is_meta_closed goalty
1371 ;;
1372 let rec first_s = function
1373   | (D _)::tl -> first_s tl
1374   | (S (g,k,c,s))::tl -> Some ((g,k,c,s),tl)
1375   | [] -> None
1376 ;;
1377 let list_union l1 l2 =
1378   (* TODO ottimizzare compare *)
1379   HExtlib.list_uniq (List.sort compare (l1 @ l1))
1380 ;;
1381 let rec eq_todo l1 l2 =
1382   match l1,l2 with
1383   | (D g1) :: tl1,(D g2) :: tl2 when g1=g2 -> eq_todo tl1 tl2
1384   | (S (g1,k1,(c1,lt1),i1)) :: tl1, (S (g2,k2,(c2,lt2),i2)) :: tl2
1385     when i1 = i2 && g1 = g2 && k1 = k2 && c1 = c2 ->
1386       if Lazy.force lt1 = Lazy.force lt2 then eq_todo tl1 tl2 else false
1387   | [],[] -> true
1388   | _ -> false
1389 ;;
1390 let eat_head todo id fl orlist = 
1391   let rec aux acc = function
1392   | [] -> [], acc
1393   | (m, s, _, _, todo1, fl1)::tl as orlist -> 
1394       let rec aux1 todo1 =
1395         match first_s todo1 with
1396         | None -> orlist, acc
1397         | Some (((gno,_,_),_,_,_), todo11) ->
1398             (* TODO confronto tra todo da ottimizzare *)
1399             if gno = id && eq_todo todo11 todo then 
1400               aux (list_union fl1 acc) tl
1401             else 
1402               aux1 todo11
1403       in
1404        aux1 todo1
1405   in 
1406     aux fl orlist
1407 ;;
1408 let close_proof p ty menv context = 
1409   let metas =
1410     List.map fst (CicUtil.metas_of_term p @ CicUtil.metas_of_term ty)
1411   in
1412   let menv = List.filter (fun (i,_,_) -> List.exists ((=)i) metas) menv in
1413   naif_closure p menv context
1414 ;;
1415 (* XXX capire bene quando aggiungere alla cache *)
1416 let add_to_cache_and_del_from_orlist_if_green_cut
1417   g s m cache key todo orlist fl ctx size minsize
1418
1419   let cache = cache_remove_underinspection cache key in
1420   (* prima per fare la irl usavamo il contesto vero e proprio e non quello 
1421    * canonico! XXX *)
1422   match calculate_closed_goal_ty g s with
1423   | None -> assert false
1424   | Some (canonical_ctx , gty) ->
1425       let goalno,depth,sort = g in
1426       let irl = mk_irl canonical_ctx in
1427       let goal = Cic.Meta(goalno, irl) in
1428       let proof = CicMetaSubst.apply_subst s goal in
1429       let green_proof, closed_proof = 
1430         let b = is_a_green_cut proof in
1431         if not b then
1432           b, (* close_proof proof gty m ctx *) proof 
1433         else
1434           b, proof
1435       in
1436       debug_print (lazy ("TENTATIVE CACHE: " ^ CicPp.ppterm key));
1437       if is_a_green_cut key then
1438         (* if the initia goal was closed, we cut alternatives *)
1439         let _ = debug_print (lazy ("MANGIO: " ^ string_of_int goalno)) in
1440         let orlist, fl = eat_head todo goalno fl orlist in
1441         let cache = 
1442           if size < minsize then 
1443             (debug_print (lazy ("NO CACHE: 2 (size <= minsize)"));cache)
1444           else 
1445           (* if the proof is closed we cache it *)
1446           if green_proof then cache_add_success cache key proof
1447           else (* cache_add_success cache key closed_proof *) 
1448             (debug_print (lazy ("NO CACHE: (no gree proof)"));cache)
1449         in
1450         cache, orlist, fl, true
1451       else
1452         let cache = 
1453           debug_print (lazy ("TENTATIVE CACHE: " ^ CicPp.ppterm gty));
1454           if size < minsize then 
1455             (debug_print (lazy ("NO CACHE: (size <= minsize)")); cache) else
1456           (* if the substituted goal and the proof are closed we cache it *)
1457           if is_a_green_cut gty then
1458             if green_proof then cache_add_success cache gty proof
1459             else (* cache_add_success cache gty closed_proof *) 
1460               (debug_print (lazy ("NO CACHE: (no green proof (gty))"));cache)
1461           else (*
1462             try
1463               let ty, _ =
1464                 CicTypeChecker.type_of_aux' ~subst:s 
1465                   m ctx closed_proof CicUniv.oblivion_ugraph
1466               in
1467               if is_a_green_cut ty then 
1468                 cache_add_success cache ty closed_proof
1469               else cache
1470             with
1471             | CicTypeChecker.TypeCheckerFailure _ ->*) 
1472           (debug_print (lazy ("NO CACHE: (no green gty )"));cache)
1473         in
1474         cache, orlist, fl, false
1475 ;;
1476 let close_failures (fl : fail list) (cache : cache) = 
1477   List.fold_left 
1478     (fun cache ((gno,depth,_),gty) -> 
1479       if CicUtil.is_meta_closed gty then
1480        ( debug_print (lazy ("FAIL: INDUCED: " ^ string_of_int gno));
1481          cache_add_failure cache gty depth) 
1482       else
1483          cache)
1484     cache fl
1485 ;;
1486 let put_in_subst subst metasenv  (goalno,_,_) canonical_ctx t ty =
1487   let entry = goalno, (canonical_ctx, t,ty) in
1488   assert_subst_are_disjoint subst [entry];
1489   let subst = entry :: subst in
1490   
1491   let metasenv = CicMetaSubst.apply_subst_metasenv subst metasenv in
1492
1493   subst, metasenv
1494 ;;
1495
1496 let mk_fake_proof metasenv subst (goalno,_,_) goalty context = 
1497   None,metasenv,subst ,(lazy (Cic.Meta(goalno,mk_irl context))),goalty, [] 
1498 ;;
1499
1500 let equational_case 
1501   tables cache depth fake_proof goalno goalty subst context 
1502     flags
1503 =
1504   let active,passive,bag = tables in
1505   let ppterm = ppterm context in
1506   let status = (fake_proof,goalno) in
1507     if flags.use_only_paramod then
1508       begin
1509         debug_print (lazy ("PARAMODULATION SU: " ^ 
1510                          string_of_int goalno ^ " " ^ ppterm goalty ));
1511         let goal_steps, saturation_steps, timeout =
1512           max_int,max_int,flags.timeout 
1513         in
1514         match
1515           Saturation.given_clause bag status active passive 
1516             goal_steps saturation_steps timeout
1517         with 
1518           | None, active, passive, bag -> 
1519               [], (active,passive,bag), cache, flags
1520           | Some(subst',(_,metasenv,_subst,proof,_, _),open_goals),active,
1521             passive,bag ->
1522               assert_subst_are_disjoint subst subst';
1523               let subst = subst@subst' in
1524               let open_goals = 
1525                 order_new_goals metasenv subst open_goals ppterm 
1526               in
1527               let open_goals = 
1528                 List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
1529               in
1530               incr candidate_no;
1531               [(!candidate_no,proof),metasenv,subst,open_goals], 
1532                 (active,passive,bag), cache, flags
1533       end
1534     else
1535       begin
1536         debug_print (lazy ("NARROWING DEL GOAL: " ^ 
1537                          string_of_int goalno ^ " " ^ ppterm goalty ));
1538         let goal_steps, saturation_steps, timeout =
1539           1,0,flags.timeout 
1540         in
1541         match
1542           Saturation.solve_narrowing bag status active passive goal_steps 
1543         with 
1544           | None, active, passive, bag -> 
1545               [], (active,passive,bag), cache, flags
1546           | Some(subst',(_,metasenv,_subst,proof,_, _),open_goals),active,
1547             passive,bag ->
1548               assert_subst_are_disjoint subst subst';
1549               let subst = subst@subst' in
1550               let open_goals = 
1551                 order_new_goals metasenv subst open_goals ppterm 
1552               in
1553               let open_goals = 
1554                 List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
1555               in
1556               incr candidate_no;
1557               [(!candidate_no,proof),metasenv,subst,open_goals], 
1558                 (active,passive,bag), cache, flags
1559       end
1560 (*
1561       begin
1562         let params = ([],["use_context","false"]) in
1563         let automation_cache = { 
1564               AutomationCache.tables = tables ;
1565               AutomationCache.univ = Universe.empty; }
1566         in
1567         try 
1568           let ((_,metasenv,subst,_,_,_),open_goals) =
1569
1570             solve_rewrite ~params ~automation_cache
1571               (fake_proof, goalno)
1572           in
1573           let proof = lazy (Cic.Meta (-1,[])) in
1574           [(!candidate_no,proof),metasenv,subst,[]],tables, cache, flags
1575         with ProofEngineTypes.Fail _ -> [], tables, cache, flags
1576 (*
1577         let res = Saturation.all_subsumed bag status active passive in
1578         let res' =
1579           List.map 
1580             (fun (subst',(_,metasenv,_subst,proof,_, _),open_goals) ->
1581                assert_subst_are_disjoint subst subst';
1582                let subst = subst@subst' in
1583                let open_goals = 
1584                  order_new_goals metasenv subst open_goals ppterm 
1585                in
1586                let open_goals = 
1587                  List.map (fun (x,sort) -> x,depth-1,sort) open_goals 
1588                in
1589                incr candidate_no;
1590                  (!candidate_no,proof),metasenv,subst,open_goals)
1591             res 
1592           in
1593           res', (active,passive,bag), cache, flags 
1594 *)
1595       end
1596 *)
1597 ;;
1598
1599 let sort_new_elems = 
1600  List.sort (fun (_,_,_,l1) (_,_,_,l2) -> 
1601          let p1 = List.length (prop_only l1) in 
1602          let p2 = List.length (prop_only l2) in
1603          if p1 = p2 then List.length l1 - List.length l2 else p1-p2)
1604 ;;
1605
1606
1607 let try_candidate dbd
1608   goalty tables subst fake_proof goalno depth context cand 
1609 =
1610   let ppterm = ppterm context in
1611   try 
1612     let actives, passives, bag = tables in 
1613     let (_,metasenv,subst,_,_,_), open_goals =
1614        ProofEngineTypes.apply_tactic
1615         (PrimitiveTactics.apply_tac ~term:cand)
1616         (fake_proof,goalno) 
1617     in
1618     let tables = actives, passives, 
1619       Equality.push_maxmeta bag 
1620         (max (Equality.maxmeta bag) (CicMkImplicit.new_meta metasenv subst)) 
1621     in
1622     debug_print (lazy ("   OK: " ^ ppterm cand));
1623     let metasenv = CicRefine.pack_coercion_metasenv metasenv in
1624     let open_goals = order_new_goals metasenv subst open_goals ppterm in
1625     let open_goals = List.map (fun (x,sort) -> x,depth-1,sort) open_goals in
1626     incr candidate_no;
1627     Some ((!candidate_no,lazy cand),metasenv,subst,open_goals), tables 
1628   with 
1629     | ProofEngineTypes.Fail s -> None,tables
1630     | CicUnification.Uncertain s ->  None,tables
1631 ;;
1632
1633 let applicative_case dbd
1634   tables depth subst fake_proof goalno goalty metasenv context universe
1635   cache flags
1636
1637   let goalty_aux = 
1638     match goalty with
1639     | Cic.Appl (hd::tl) -> 
1640         Cic.Appl (hd :: HExtlib.mk_list (Cic.Meta (0,[])) (List.length tl))
1641     | _ -> goalty
1642   in
1643   let candidates = 
1644     get_candidates flags.skip_trie_filtering universe cache goalty_aux
1645   in
1646   let tables, elems = 
1647     List.fold_left 
1648       (fun (tables,elems) cand ->
1649         match 
1650           try_candidate dbd goalty
1651             tables subst fake_proof goalno depth context cand
1652         with
1653         | None, tables -> tables, elems
1654         | Some x, tables -> tables, x::elems)
1655       (tables,[]) candidates
1656   in
1657   let elems = sort_new_elems elems in
1658   elems, tables, cache
1659 ;;
1660
1661 let try_smart_candidate dbd
1662   goalty tables subst fake_proof goalno depth context cand 
1663 =
1664   let ppterm = ppterm context in
1665   try
1666     let params = ([],[]) in
1667     let automation_cache = { 
1668           AutomationCache.tables = tables ;
1669           AutomationCache.univ = Universe.empty; }
1670     in
1671     debug_print (lazy ("candidato per " ^ string_of_int goalno 
1672       ^ ": " ^ CicPp.ppterm cand));
1673 (*
1674     let (_,metasenv,subst,_,_,_) = fake_proof in
1675     prerr_endline ("metasenv:\n" ^ CicMetaSubst.ppmetasenv [] metasenv);
1676     prerr_endline ("subst:\n" ^ CicMetaSubst.ppsubst ~metasenv subst);
1677 *)
1678     let ((_,metasenv,subst,_,_,_),open_goals) =
1679       apply_smart ~dbd ~term:cand ~params ~automation_cache
1680         (fake_proof, goalno)
1681     in
1682     let metasenv = CicRefine.pack_coercion_metasenv metasenv in
1683     let open_goals = order_new_goals metasenv subst open_goals ppterm in
1684     let open_goals = List.map (fun (x,sort) -> x,depth-1,sort) open_goals in
1685     incr candidate_no;
1686     Some ((!candidate_no,lazy cand),metasenv,subst,open_goals), tables 
1687   with 
1688   | ProofEngineTypes.Fail s -> None,tables
1689   | CicUnification.Uncertain s ->  None,tables
1690 ;;
1691
1692 let smart_applicative_case dbd
1693   tables depth subst fake_proof goalno goalty metasenv context universe
1694   cache flags
1695
1696   let signature = MetadataQuery.signature_of metasenv goalno in
1697   let goalty_aux = 
1698     match goalty with
1699     | Cic.Appl (hd::tl) -> 
1700         Cic.Appl (hd :: HExtlib.mk_list (Cic.Meta (0,[])) (List.length tl))
1701     | _ -> goalty
1702   in
1703   let smart_candidates = 
1704     get_candidates flags.skip_trie_filtering universe cache goalty_aux
1705   in
1706   let candidates = 
1707     get_candidates flags.skip_trie_filtering universe cache goalty
1708   in
1709   let smart_candidates = 
1710     List.filter
1711       (fun x -> not(List.mem x candidates)) smart_candidates
1712   in 
1713   let debug_msg =
1714     (lazy ("smart_candidates" ^ " = " ^ 
1715              (String.concat "\n" (List.map CicPp.ppterm smart_candidates)))) in
1716   debug_print debug_msg;
1717   let candidates = List.filter (only signature context metasenv) candidates in
1718   let smart_candidates = 
1719     List.filter (only signature context metasenv) smart_candidates 
1720   in
1721 (*
1722   let penalty cand depth = 
1723     if only signature context metasenv cand then depth else ((prerr_endline (
1724     "penalizzo " ^ CicPp.ppterm cand));depth -1)
1725   in
1726 *)
1727   let tables, elems = 
1728     List.fold_left 
1729       (fun (tables,elems) cand ->
1730         match 
1731           try_candidate dbd goalty
1732             tables subst fake_proof goalno depth context cand
1733         with
1734         | None, tables ->
1735             (* if normal application fails we try to be smart *)
1736             (match try_smart_candidate dbd goalty
1737                tables subst fake_proof goalno depth context cand
1738              with
1739                | None, tables -> tables, elems
1740                | Some x, tables -> tables, x::elems)
1741         | Some x, tables -> tables, x::elems)
1742       (tables,[]) candidates
1743   in
1744   let tables, smart_elems = 
1745       List.fold_left 
1746         (fun (tables,elems) cand ->
1747           match 
1748             try_smart_candidate dbd goalty
1749               tables subst fake_proof goalno depth context cand
1750           with
1751           | None, tables -> tables, elems
1752           | Some x, tables -> tables, x::elems)
1753         (tables,[]) smart_candidates
1754   in
1755   let elems = sort_new_elems (elems @ smart_elems) in
1756   elems, tables, cache
1757 ;;
1758
1759 let equational_and_applicative_case dbd
1760   universe flags m s g gty tables cache context 
1761 =
1762   let goalno, depth, sort = g in
1763   let fake_proof = mk_fake_proof m s g gty context in
1764   if is_equational_case gty flags then
1765     let elems,tables,cache, flags =
1766       equational_case tables cache
1767         depth fake_proof goalno gty s context flags 
1768     in
1769     let more_elems, tables, cache =
1770       if flags.use_only_paramod then
1771         [],tables, cache
1772       else
1773         applicative_case dbd
1774           tables depth s fake_proof goalno 
1775             gty m context universe cache flags
1776     in
1777       elems@more_elems, tables, cache, flags            
1778   else
1779     let elems, tables, cache =
1780       match LibraryObjects.eq_URI () with
1781       | Some _ ->
1782          smart_applicative_case dbd tables depth s fake_proof goalno 
1783            gty m context universe cache flags
1784       | None -> 
1785          applicative_case dbd tables depth s fake_proof goalno 
1786            gty m context universe cache flags
1787     in
1788       elems, tables, cache, flags  
1789 ;;
1790 let rec condition_for_hint i = function
1791   | [] -> false
1792   | S (_,_,(j,_),_):: tl -> j <> i (* && condition_for_hint i tl *)
1793   | _::tl -> condition_for_hint i tl
1794 ;;
1795 let remove_s_from_fl (id,_,_) (fl : fail list) =
1796   let rec aux = function
1797     | [] -> []
1798     | ((id1,_,_),_)::tl when id = id1 -> tl
1799     | hd::tl ->  hd :: aux tl
1800   in 
1801     aux fl
1802 ;;
1803
1804 let prunable_for_size flags s m todo =
1805   let rec aux b = function
1806     | (S _)::tl -> aux b tl
1807     | (D (_,_,T))::tl -> aux b tl
1808     | (D g)::tl -> 
1809         (match calculate_goal_ty g s m with
1810           | None -> aux b tl
1811           | Some (canonical_ctx, gty) -> 
1812             let gsize, _ = 
1813               Utils.weight_of_term 
1814                 ~consider_metas:false ~count_metas_occurrences:true gty in
1815             let newb = b || gsize > flags.maxgoalsizefactor in
1816             aux newb tl)
1817     | [] -> b
1818   in
1819     aux false todo
1820
1821 (*
1822 let prunable ty todo =
1823   let rec aux b = function
1824     | (S(_,k,_,_))::tl -> aux (b || Equality.meta_convertibility k ty) tl
1825     | (D (_,_,T))::tl -> aux b tl
1826     | D _::_ -> false
1827     | [] -> b
1828   in
1829     aux false todo
1830 ;;
1831 *)
1832
1833 let prunable menv subst ty todo =
1834   let rec aux = function
1835     | (S(_,k,_,_))::tl ->
1836          (match Equality.meta_convertibility_subst k ty menv with
1837           | None -> aux tl
1838           | Some variant -> 
1839                no_progress variant tl (* || aux tl*))
1840     | (D (_,_,T))::tl -> aux tl
1841     | _ -> false
1842   and no_progress variant = function
1843     | [] -> (*prerr_endline "++++++++++++++++++++++++ no_progress";*) true
1844     | D ((n,_,P) as g)::tl -> 
1845         (match calculate_goal_ty g subst menv with
1846            | None -> no_progress variant tl
1847            | Some (_, gty) -> 
1848                (match calculate_goal_ty g variant menv with
1849                   | None -> assert false
1850                   | Some (_, gty') ->
1851                       if gty = gty' then no_progress variant tl
1852 (* 
1853 (prerr_endline (string_of_int n);
1854  prerr_endline (CicPp.ppterm gty);
1855  prerr_endline (CicPp.ppterm gty');
1856  prerr_endline "---------- subst";
1857  prerr_endline (CicMetaSubst.ppsubst ~metasenv:menv subst);
1858  prerr_endline "---------- variant";
1859  prerr_endline (CicMetaSubst.ppsubst ~metasenv:menv variant);
1860  prerr_endline "---------- menv";
1861  prerr_endline (CicMetaSubst.ppmetasenv [] menv); 
1862                          no_progress variant tl) *)
1863                       else false))
1864     | _::tl -> no_progress variant tl
1865   in
1866     aux todo
1867
1868 ;;
1869 let condition_for_prune_hint prune (m, s, size, don, todo, fl) =
1870   let s = 
1871     HExtlib.filter_map (function S (_,_,(c,_),_) -> Some c | _ -> None) todo 
1872   in
1873   List.for_all (fun i -> List.for_all (fun j -> i<>j) prune) s
1874 ;;
1875 let filter_prune_hint c l =
1876   let prune = !prune_hint in
1877   prune_hint := []; (* possible race... *)
1878   if prune = [] then c,l
1879   else 
1880     cache_reset_underinspection c,      
1881     List.filter (condition_for_prune_hint prune) l
1882 ;;
1883 let auto_main dbd tables context flags 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                         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 goals = order_new_goals metasenv [] gl CicPp.ppterm in
2045   let goals = 
2046     List.map 
2047       (fun (x,s) -> D (x,flags.maxdepth,s)) goals 
2048   in
2049   let elems = [metasenv,[],1,[],goals,[]] in
2050   let rec aux tables solutions cache elems flags =
2051     match auto_main dbd tables context flags universe cache elems with
2052     | Gaveup (tables,cache) ->
2053         solutions,cache, tables
2054     | Proved (metasenv,subst,others,tables,cache) -> 
2055         if Unix.gettimeofday () > flags.timeout then
2056           ((subst,metasenv)::solutions), cache, tables
2057         else
2058           aux tables ((subst,metasenv)::solutions) cache others flags
2059   in
2060   let rc = aux tables [] cache elems flags in
2061     match rc with
2062     | [],cache,tables -> [],cache,tables
2063     | solutions, cache,tables -> 
2064         let solutions = 
2065           HExtlib.filter_map
2066             (fun (subst,newmetasenv) ->
2067               let opened = 
2068                 ProofEngineHelpers.compare_metasenvs ~oldmetasenv:metasenv ~newmetasenv
2069               in
2070               if opened = [] then Some subst else None)
2071             solutions
2072         in
2073          solutions,cache,tables
2074 ;;
2075
2076 (******************* AUTO ***************)
2077
2078 let auto dbd flags metasenv tables universe cache context metasenv gl =
2079   let initial_time = Unix.gettimeofday() in
2080   let goals = order_new_goals metasenv [] gl CicPp.ppterm in
2081   let goals = List.map (fun (x,s) -> D(x,flags.maxdepth,s)) goals in
2082   let elems = [metasenv,[],1,[],goals,[]] in
2083   match auto_main dbd tables context flags universe cache elems with
2084   | Proved (metasenv,subst,_, tables,cache) -> 
2085       debug_print(lazy
2086         ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
2087       Some (subst,metasenv), cache
2088   | Gaveup (tables,cache) -> 
2089       debug_print(lazy
2090         ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
2091       None,cache
2092 ;;
2093
2094 let auto_tac ~(dbd:HSql.dbd) ~params:(univ,params) ~automation_cache (proof, goal) =
2095   let flags = flags_of_params params () in
2096   let use_library = flags.use_library in
2097   let universe, tables, cache =
2098     init_cache_and_tables 
2099      ~dbd ~use_library ~use_context:(not flags.skip_context)
2100      automation_cache univ (proof, goal) 
2101   in
2102   let _,metasenv,subst,_,_, _ = proof in
2103   let _,context,goalty = CicUtil.lookup_meta goal metasenv in
2104   let tables,cache =
2105     if flags.close_more then
2106       close_more 
2107         tables context (proof, goal) 
2108           (auto_all_solutions dbd) universe cache 
2109     else tables,cache in
2110   let initial_time = Unix.gettimeofday() in
2111   let (_,oldmetasenv,_,_,_, _) = proof in
2112   hint := None;
2113   let elem = 
2114     metasenv,subst,1,[],[D (goal,flags.maxdepth,P)],[]
2115   in
2116   match auto_main dbd tables context flags universe cache [elem] with
2117     | Proved (metasenv,subst,_, tables,cache) -> 
2118         debug_print (lazy 
2119           ("TIME:"^string_of_float(Unix.gettimeofday()-.initial_time)));
2120         let proof,metasenv =
2121         ProofEngineHelpers.subst_meta_and_metasenv_in_proof
2122           proof goal subst metasenv
2123         in
2124         let opened = 
2125           ProofEngineHelpers.compare_metasenvs ~oldmetasenv
2126             ~newmetasenv:metasenv
2127         in
2128           proof,opened
2129     | Gaveup (tables,cache) -> 
2130         debug_print
2131           (lazy ("TIME:"^
2132             string_of_float(Unix.gettimeofday()-.initial_time)));
2133         raise (ProofEngineTypes.Fail (lazy "Auto gave up"))
2134 ;;
2135
2136 let auto_tac ~dbd ~params ~automation_cache = 
2137   ProofEngineTypes.mk_tactic (auto_tac ~params ~dbd ~automation_cache);;
2138
2139 let pp_proofterm = Equality.pp_proofterm;;
2140
2141 let revision = "$Revision$";;
2142 let size_and_depth context metasenv t = 100, 100