]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/tactics/paramodulation/utils.ml
Preparing for 0.5.9 release.
[helm.git] / helm / software / components / tactics / paramodulation / utils.ml
1 (* Copyright (C) 2005, 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 (* $Id$ *)
27
28 let time = false;;
29 let debug = false;;
30 let debug_metas = false;; 
31 let debug_res = false;;
32
33 let debug_print s = if debug then prerr_endline (Lazy.force s);;
34
35 let print_metasenv metasenv =
36   String.concat "\n--------------------------\n"
37     (List.map (fun (i, context, term) ->
38                  (string_of_int i) ^ " [\n" ^ (CicPp.ppcontext context) ^
39                    "\n] " ^  (CicPp.ppterm term))
40        metasenv)
41 ;;
42
43
44 let print_subst ?(prefix="\n") subst =
45     String.concat prefix
46      (List.map
47        (fun (i, (c, t, ty)) ->
48           Printf.sprintf "?%d -> %s : %s" i
49             (CicPp.ppterm t) (CicPp.ppterm ty))
50        subst)
51 ;;  
52
53 type comparison = Lt | Le | Eq | Ge | Gt | Incomparable;;
54     
55 let string_of_comparison = function
56   | Lt -> "<"
57   | Le -> "<="
58   | Gt -> ">"
59   | Ge -> ">="
60   | Eq -> "="
61   | Incomparable -> "I"
62
63 type environment = Cic.metasenv * Cic.context * CicUniv.universe_graph
64
65 module OrderedTerm =
66 struct
67   type t = Cic.term
68       
69   let compare = Pervasives.compare
70 end
71
72 module TermSet = Set.Make(OrderedTerm);;
73 module TermMap = Map.Make(OrderedTerm);;
74
75 let symbols_of_term term =
76   let module C = Cic in
77   let rec aux map = function
78     | C.Meta _ -> map
79     | C.Appl l ->
80         List.fold_left (fun res t -> (aux res t)) map l
81     | t ->
82         let map = 
83           try
84             let c = TermMap.find t map in
85             TermMap.add t (c+1) map
86           with Not_found ->
87             TermMap.add t 1 map
88         in
89         map
90   in
91   aux TermMap.empty term
92 ;;
93
94
95 let metas_of_term term =
96   let module C = Cic in
97   let rec aux = function
98     | C.Meta _ as t -> TermSet.singleton t
99     | C.Appl l ->
100         List.fold_left (fun res t -> TermSet.union res (aux t)) TermSet.empty l
101     | C.Lambda(n,s,t) ->
102         TermSet.union (aux s) (aux t)
103     | C.Prod(n,s,t) ->
104         TermSet.union (aux s) (aux t)
105     | C.LetIn(n,s,ty,t) ->
106         TermSet.union (aux s) (TermSet.union (aux ty) (aux t))
107     | t -> TermSet.empty (* TODO: maybe add other cases? *)
108   in
109   aux term
110 ;;
111
112 let rec remove_local_context =
113   function
114     | Cic.Meta (i,_) -> Cic.Meta (i,[])
115     | Cic.Appl l ->
116        Cic.Appl(List.map remove_local_context l)
117     | Cic.Prod (n,s,t) -> 
118        Cic.Prod (n,remove_local_context s, remove_local_context t)
119     | t -> t 
120
121
122 (************************* rpo ********************************)
123 let number = [
124   UriManager.uri_of_string "cic:/Coq/Init/Datatypes/nat.ind#xpointer(1/1)",3;
125   UriManager.uri_of_string "cic:/Coq/Init/Datatypes/nat.ind#xpointer(1/1/1)",6;
126   UriManager.uri_of_string "cic:/Coq/Init/Datatypes/nat.ind#xpointer(1/1/2)",9;
127   HelmLibraryObjects.Peano.pred_URI, 12;
128   HelmLibraryObjects.Peano.plus_URI, 15;
129   HelmLibraryObjects.Peano.minus_URI, 18;
130   HelmLibraryObjects.Peano.mult_URI, 21;
131   UriManager.uri_of_string "cic:/matita/nat/nat/nat.ind#xpointer(1/1)",103;
132   UriManager.uri_of_string "cic:/matita/nat/nat/nat.ind#xpointer(1/1/1)",106;
133   UriManager.uri_of_string "cic:/matita/nat/nat/nat.ind#xpointer(1/1/2)",109;
134   UriManager.uri_of_string "cic:/matita/nat/nat/pred.con",112;
135   UriManager.uri_of_string "cic:/matita/nat/plus/plus.con",115;
136   UriManager.uri_of_string "cic:/matita/nat/minus/minus.con",118;
137   UriManager.uri_of_string "cic:/matita/nat/times/times.con",121;
138   ]
139 ;;
140
141 let atomic t =
142   match t with
143       Cic.Const _ 
144     | Cic.MutInd _ 
145     | Cic.MutConstruct _ 
146     | Cic.Rel _ -> true
147     | _ -> false
148
149 let sig_order_const t1 t2 =
150   try
151     let u1 = CicUtil.uri_of_term t1 in
152     let u2 = CicUtil.uri_of_term t2 in  
153     let n1 = List.assoc u1 number in
154     let n2 = List.assoc u2 number in
155     if n1 < n2 then Lt
156     else if n1 > n2 then Gt
157     else 
158       begin
159         prerr_endline ("t1 = "^(CicPp.ppterm t1));
160         prerr_endline ("t2 = "^(CicPp.ppterm t2)); 
161         assert false
162       end
163   with 
164       Invalid_argument _ 
165     | Not_found -> Incomparable
166
167 let sig_order t1 t2 =
168   match t1, t2 with
169       Cic.Rel n, Cic.Rel m when n < m -> Gt (* inverted order *)
170     | Cic.Rel n, Cic.Rel m when n = m -> Incomparable
171     | Cic.Rel n, Cic.Rel m when n > m -> Lt
172     | Cic.Rel _, _ -> Gt
173     | _, Cic.Rel _ -> Lt
174     | _,_ -> sig_order_const t1 t2
175
176 let rec rpo_lt t1 t2 =
177   let module C = Cic in 
178   let first_trie =
179     match t1,t2 with 
180         C.Meta (_, _), C.Meta (_,_) -> false
181       | C.Meta (_,_) , t2 -> TermSet.mem t1 (metas_of_term t2)
182       | t1, C.Meta (_,_) -> false
183       | C.Appl [h1;a1],C.Appl [h2;a2] when h1=h2 -> 
184           rpo_lt a1 a2
185       | C.Appl (h1::arg1),C.Appl (h2::arg2) when h1=h2 ->
186           if lex_lt arg1 arg2 then
187             check_lt arg1 t2 
188           else false
189       | C.Appl (h1::arg1),C.Appl (h2::arg2) -> 
190           (match sig_order h1 h2 with
191              | Lt -> check_lt arg1 t2
192              | _ -> false)
193       | C.Appl (h1::arg1), t2 when atomic t2 ->
194           (match sig_order h1 t2 with
195              | Lt -> check_lt arg1 t2
196              | _ -> false)
197       | t1 , C.Appl (h2::arg2) when atomic t1 ->
198           (match sig_order t1 h2 with
199              | Lt -> true
200              | _ -> false )
201       | C.Appl [] , _ -> assert false 
202       | _ , C.Appl [] -> assert false
203       | t1, t2 when (atomic t1 && atomic t2 && t1<>t2) ->
204           (match sig_order t1 t2 with
205              | Lt -> true
206              | _ -> false)
207       | _,_ -> false
208   in
209   if first_trie then true else
210   match t2 with
211       C.Appl (_::args) ->
212         List.exists (fun a -> t1 = a || rpo_lt t1 a) args
213     | _ -> false
214  
215 and lex_lt l1 l2 = 
216   match l1,l2 with
217       [],[] -> false
218     | [],_ -> assert false
219     | _, [] -> assert false
220     | a1::l1, a2::l2 when a1 = a2 -> lex_lt l1 l2
221     | a1::_, a2::_ -> rpo_lt a1 a2
222  
223 and check_lt l t =
224   List.fold_left 
225     (fun b a -> b && (rpo_lt a t))
226     true l
227 ;;
228
229 let rpo t1 t2 =
230   if rpo_lt t2 t1 then Gt
231   else if rpo_lt t1 t2 then Lt
232   else Incomparable
233
234
235 (*********************** fine rpo *****************************)
236
237 (* (weight of constants, [(meta, weight_of_meta)]) *)
238 type weight = int * (int * int) list;;
239
240 let string_of_weight (cw, mw) =
241   let s =
242     String.concat ", "
243       (List.map (function (m, w) -> Printf.sprintf "(%d,%d)" m w) mw)
244   in
245   Printf.sprintf "[%d; %s]" cw s
246
247
248 let weight_of_term ?(consider_metas=true) ?(count_metas_occurrences=false) term =
249   let module C = Cic in
250   let vars_dict = Hashtbl.create 5 in
251   let rec aux = function
252     | C.Meta (metano, _) when consider_metas ->
253         (try
254            let oldw = Hashtbl.find vars_dict metano in
255            Hashtbl.replace vars_dict metano (oldw+1)
256          with Not_found ->
257            Hashtbl.add vars_dict metano 1);
258         if count_metas_occurrences then 1 else 0
259     | C.Meta _ ->  (* "variables" are lighter than constants and functions...*)
260         if count_metas_occurrences then 1 else 0         
261     | C.Var (_, ens)
262     | C.Const (_, ens)
263     | C.MutInd (_, _, ens)
264     | C.MutConstruct (_, _, _, ens) ->
265         List.fold_left (fun w (u, t) -> (aux t) + w) 1 ens
266          
267     | C.Cast (t1, t2)
268     | C.Lambda (_, t1, t2)
269     | C.Prod (_, t1, t2)
270     | C.LetIn (_, t1, _, t2) ->
271         let w1 = aux t1 in
272         let w2 = aux t2 in
273         w1 + w2 + 1
274           
275     | C.Appl l -> List.fold_left (+) 0 (List.map aux l)
276         
277     | C.MutCase (_, _, outt, t, pl) ->
278         let w1 = aux outt in
279         let w2 = aux t in
280         let w3 = List.fold_left (+) 0 (List.map aux pl) in
281         w1 + w2 + w3 + 1
282           
283     | C.Fix (_, fl) ->
284         List.fold_left (fun w (n, i, t1, t2) -> (aux t1) + (aux t2) + w) 1 fl
285           
286     | C.CoFix (_, fl) ->
287         List.fold_left (fun w (n, t1, t2) -> (aux t1) + (aux t2) + w) 1 fl
288           
289     | _ -> 1
290   in
291   let w = aux term in
292   let l =
293     Hashtbl.fold (fun meta metaw resw -> (meta, metaw)::resw) vars_dict [] in
294   let compare w1 w2 = 
295     match w1, w2 with
296     | (m1, _), (m2, _) -> m2 - m1 
297   in 
298   (w, List.sort compare l) (* from the biggest meta to the smallest (0) *)
299 ;;
300
301
302 module OrderedInt = struct
303   type t = int
304
305   let compare = Pervasives.compare
306 end
307
308 module IntSet = Set.Make(OrderedInt)
309
310 let goal_symbols = ref TermSet.empty
311
312 let set_of_map m = 
313   TermMap.fold (fun k _ s -> TermSet.add k s) m TermSet.empty
314 ;;
315
316 let set_goal_symbols term = 
317   let m = symbols_of_term term in
318   goal_symbols := (set_of_map m)
319 ;;
320
321 let symbols_of_eq (ty,left,right,_) = 
322   let sty = set_of_map (symbols_of_term ty) in
323   let sl = set_of_map (symbols_of_term left) in
324   let sr = set_of_map (symbols_of_term right) in
325   TermSet.union sty (TermSet.union sl sr)
326 ;;
327
328 let distance sgoal seq =
329   let s = TermSet.diff seq sgoal in
330   TermSet.cardinal s
331 ;;
332
333 let compute_equality_weight (ty,left,right,o) =
334   let factor = 2 in
335   match o with
336     | Lt -> 
337         let w, m = (weight_of_term 
338                ~consider_metas:true ~count_metas_occurrences:false right) in
339           w + (factor * (List.length m)) ;
340     | Le -> assert false
341     | Gt -> 
342         let w, m = (weight_of_term 
343                ~consider_metas:true ~count_metas_occurrences:false left) in
344           w + (factor * (List.length m)) ;
345   | Ge -> assert false
346   | Eq 
347   | Incomparable -> 
348       let w1, m1 = (weight_of_term 
349                ~consider_metas:true ~count_metas_occurrences:false right) in
350       let w2, m2 = (weight_of_term 
351                ~consider_metas:true ~count_metas_occurrences:false left) in
352       w1 + w2 + (factor * (List.length m1)) + (factor * (List.length m2))
353 ;;
354
355 let compute_equality_weight e =
356   let w = compute_equality_weight e in
357   let d = 0 in (* distance !goal_symbols (symbols_of_eq e) in *)
358 (*
359   prerr_endline (Printf.sprintf "dist %s --- %s === %d" 
360    (String.concat ", " (List.map (CicPp.ppterm) (TermSet.elements
361      !goal_symbols)))
362    (String.concat ", " (List.map (CicPp.ppterm) (TermSet.elements
363      (symbols_of_eq e))))
364    d
365   );
366 *)
367   w + d 
368 ;;
369
370 (* old
371 let compute_equality_weight (ty,left,right,o) =
372   let metasw = ref 0 in
373   let weight_of t =
374     let w, m = (weight_of_term 
375                   ~consider_metas:true ~count_metas_occurrences:false t) in
376     metasw := !metasw + (1 * (List.length m)) ;
377     w
378   in
379   (* Warning: the following let cannot be expanded since it forces the
380      right evaluation order!!!! *)
381   let w = (weight_of ty) + (weight_of left) + (weight_of right) in 
382   (* let w = weight_of (Cic.Appl [ty;left;right]) in *)
383   w + !metasw
384 ;;
385 *)
386
387 (* returns a "normalized" version of the polynomial weight wl (with type
388  * weight list), i.e. a list sorted ascending by meta number,
389  * from 0 to maxmeta. wl must be sorted descending by meta number. Example:
390  * normalize_weight 5 (3, [(3, 2); (1, 1)]) ->
391  *      (3, [(1, 1); (2, 0); (3, 2); (4, 0); (5, 0)]) *)
392 let normalize_weight maxmeta (cw, wl) =
393   let rec aux = function
394     | 0 -> []
395     | m -> (m, 0)::(aux (m-1))
396   in
397   let tmpl = aux maxmeta in
398   let wl =
399     List.sort
400       (fun (m, _) (n, _) -> Pervasives.compare m n)
401       (List.fold_left
402          (fun res (m, w) -> (m, w)::(List.remove_assoc m res)) tmpl wl)
403   in
404   (cw, wl)
405 ;;
406
407
408 let normalize_weights (cw1, wl1) (cw2, wl2) =
409   let rec aux wl1 wl2 =
410     match wl1, wl2 with
411     | [], [] -> [], []
412     | (m, w)::tl1, (n, w')::tl2 when m = n ->
413         let res1, res2 = aux tl1 tl2 in
414         (m, w)::res1, (n, w')::res2
415     | (m, w)::tl1, ((n, w')::_ as wl2) when m < n ->
416         let res1, res2 = aux tl1 wl2 in
417         (m, w)::res1, (m, 0)::res2
418     | ((m, w)::_ as wl1), (n, w')::tl2 when m > n ->
419         let res1, res2 = aux wl1 tl2 in
420         (n, 0)::res1, (n, w')::res2
421     | [], (n, w)::tl2 ->
422         let res1, res2 = aux [] tl2 in
423         (n, 0)::res1, (n, w)::res2
424     | (m, w)::tl1, [] ->
425         let res1, res2 = aux tl1 [] in
426         (m, w)::res1, (m, 0)::res2
427     | _, _ -> assert false
428   in
429   let cmp (m, _) (n, _) = compare m n in
430   let wl1, wl2 = aux (List.sort cmp wl1) (List.sort cmp wl2) in
431   (cw1, wl1), (cw2, wl2)
432 ;;
433
434         
435 let compare_weights ?(normalize=false)
436     ((h1, w1) as weight1) ((h2, w2) as weight2)=
437   let (h1, w1), (h2, w2) =
438     if normalize then
439       normalize_weights weight1 weight2
440     else
441       (h1, w1), (h2, w2)
442   in
443   let res, diffs =
444     try
445       List.fold_left2
446         (fun ((lt, eq, gt), diffs) w1 w2 ->
447            match w1, w2 with
448            | (meta1, w1), (meta2, w2) when meta1 = meta2 ->
449                let diffs = (w1 - w2) + diffs in 
450                let r = compare w1 w2 in
451                if r < 0 then (lt+1, eq, gt), diffs
452                else if r = 0 then (lt, eq+1, gt), diffs
453                else (lt, eq, gt+1), diffs
454            | (meta1, w1), (meta2, w2) ->
455                debug_print
456                  (lazy
457                     (Printf.sprintf "HMMM!!!! %s, %s\n"
458                        (string_of_weight weight1) (string_of_weight weight2)));
459                assert false)
460         ((0, 0, 0), 0) w1 w2
461     with Invalid_argument _ ->
462       debug_print
463         (lazy
464            (Printf.sprintf "Invalid_argument: %s{%s}, %s{%s}, normalize = %s\n"
465               (string_of_weight (h1, w1)) (string_of_weight weight1)
466               (string_of_weight (h2, w2)) (string_of_weight weight2)
467               (string_of_bool normalize)));
468       assert false
469   in
470   let hdiff = h1 - h2 in 
471   match res with
472   | (0, _, 0) ->
473       if hdiff < 0 then Lt
474       else if hdiff > 0 then Gt
475       else Eq (* Incomparable *)
476   | (m, _, 0) ->
477       if hdiff <= 0 then Lt
478       else if (- diffs) >= hdiff then Le else Incomparable
479   | (0, _, m) ->
480       if hdiff >= 0 then Gt
481       else if diffs >= (- hdiff) then Ge else Incomparable
482   | (m, _, n) when m > 0 && n > 0 ->
483       Incomparable
484   | _ -> assert false 
485 ;;
486
487
488 let rec aux_ordering ?(recursion=true) t1 t2 =
489   let module C = Cic in
490   let compare_uris u1 u2 =
491     let res =
492       compare (UriManager.string_of_uri u1) (UriManager.string_of_uri u2) in
493     if res < 0 then Lt
494     else if res = 0 then Eq
495     else Gt
496   in
497   match t1, t2 with
498   | C.Meta _, _
499   | _, C.Meta _ -> Incomparable
500
501   | t1, t2 when t1 = t2 -> Eq
502
503   | C.Rel n, C.Rel m -> if n > m then Lt else Gt
504   | C.Rel _, _ -> Lt
505   | _, C.Rel _ -> Gt
506
507   | C.Const (u1, _), C.Const (u2, _) -> compare_uris u1 u2
508   | C.Const _, _ -> Lt
509   | _, C.Const _ -> Gt
510
511   | C.MutInd (u1, tno1, _), C.MutInd (u2, tno2, _) -> 
512        let res =  compare_uris u1 u2 in
513        if res <> Eq then res 
514        else 
515           let res = compare tno1 tno2 in
516           if res = 0 then Eq else if res < 0 then Lt else Gt
517   | C.MutInd _, _ -> Lt
518   | _, C.MutInd _ -> Gt
519
520   | C.MutConstruct (u1, tno1, cno1, _), C.MutConstruct (u2, tno2, cno2, _) ->
521        let res =  compare_uris u1 u2 in
522        if res <> Eq then res 
523        else 
524           let res = compare (tno1,cno1) (tno2,cno2) in
525           if res = 0 then Eq else if res < 0 then Lt else Gt
526   | C.MutConstruct _, _ -> Lt
527   | _, C.MutConstruct _ -> Gt
528
529   | C.Appl l1, C.Appl l2 when recursion ->
530       let rec cmp t1 t2 =
531         match t1, t2 with
532         | [], [] -> Eq
533         | _, [] -> Gt
534         | [], _ -> Lt
535         | hd1::tl1, hd2::tl2 ->
536             let o = aux_ordering hd1 hd2 in
537             if o = Eq then cmp tl1 tl2
538             else o
539       in
540       cmp l1 l2
541   | C.Appl (h1::t1), C.Appl (h2::t2) when not recursion ->
542       aux_ordering h1 h2
543         
544   | t1, t2 ->
545       debug_print
546         (lazy
547            (Printf.sprintf "These two terms are not comparable:\n%s\n%s\n\n"
548               (CicPp.ppterm t1) (CicPp.ppterm t2)));
549       Incomparable
550 ;;
551
552
553 (* w1, w2 are the weights, they should already be normalized... *)
554 let nonrec_kbo_w (t1, w1) (t2, w2) =
555   match compare_weights w1 w2 with
556   | Le -> if aux_ordering t1 t2 = Lt then Lt else Incomparable
557   | Ge -> if aux_ordering t1 t2 = Gt then Gt else Incomparable
558   | Eq -> aux_ordering t1 t2
559   | res -> res
560 ;;
561
562     
563 let nonrec_kbo t1 t2 =
564   let w1 = weight_of_term t1 in
565   let w2 = weight_of_term t2 in
566   (*
567   prerr_endline ("weight1 :"^(string_of_weight w1));
568   prerr_endline ("weight2 :"^(string_of_weight w2)); 
569   *)
570   match compare_weights ~normalize:true w1 w2 with
571   | Le -> if aux_ordering t1 t2 = Lt then Lt else Incomparable
572   | Ge -> if aux_ordering t1 t2 = Gt then Gt else Incomparable
573   | Eq -> aux_ordering t1 t2
574   | res -> res
575 ;;
576
577
578 let rec kbo t1 t2 =
579   let aux = aux_ordering ~recursion:false in
580   let w1 = weight_of_term t1
581   and w2 = weight_of_term t2 in
582   let rec cmp t1 t2 =
583     match t1, t2 with
584     | [], [] -> Eq
585     | _, [] -> Gt
586     | [], _ -> Lt
587     | hd1::tl1, hd2::tl2 ->
588         let o =
589           kbo hd1 hd2
590         in
591         if o = Eq then cmp tl1 tl2
592         else o
593   in
594   let comparison = compare_weights ~normalize:true w1 w2 in
595   match comparison with
596   | Le ->
597       let r = aux t1 t2 in
598       if r = Lt then Lt
599       else if r = Eq then (
600         match t1, t2 with
601         | Cic.Appl (h1::tl1), Cic.Appl (h2::tl2) when h1 = h2 ->
602             if cmp tl1 tl2 = Lt then Lt else Incomparable
603         | _, _ ->  Incomparable
604       ) else Incomparable
605   | Ge ->
606       let r = aux t1 t2 in
607       if r = Gt then Gt
608       else if r = Eq then (
609         match t1, t2 with
610         | Cic.Appl (h1::tl1), Cic.Appl (h2::tl2) when h1 = h2 ->
611             if cmp tl1 tl2 = Gt then Gt else Incomparable
612         | _, _ ->  Incomparable
613       ) else Incomparable
614   | Eq ->
615       let r = aux t1 t2 in
616       if r = Eq then (
617         match t1, t2 with
618         | Cic.Appl (h1::tl1), Cic.Appl (h2::tl2) when h1 = h2 ->
619             cmp tl1 tl2
620         | _, _ ->  Incomparable
621       ) else r 
622   | res -> res
623 ;;
624           
625 let rec ao t1 t2 =
626   let get_hd t =
627     match t with
628         Cic.MutConstruct(uri,tyno,cno,_) -> Some(uri,tyno,cno)
629       | Cic.Appl(Cic.MutConstruct(uri,tyno,cno,_)::_) -> 
630           Some(uri,tyno,cno)
631       | _ -> None in
632   let aux = aux_ordering ~recursion:false in
633   let w1 = weight_of_term t1
634   and w2 = weight_of_term t2 in
635   let rec cmp t1 t2 =
636     match t1, t2 with
637     | [], [] -> Eq
638     | _, [] -> Gt
639     | [], _ -> Lt
640     | hd1::tl1, hd2::tl2 ->
641         let o =
642           ao hd1 hd2
643         in
644         if o = Eq then cmp tl1 tl2
645         else o
646   in
647   match get_hd t1, get_hd t2 with
648       Some(_),None -> Lt
649     | None,Some(_) -> Gt
650     | _ ->
651         let comparison = compare_weights ~normalize:true w1 w2 in
652           match comparison with
653             | Le ->
654                 let r = aux t1 t2 in
655                   if r = Lt then Lt
656                   else if r = Eq then (
657                     match t1, t2 with
658                       | Cic.Appl (h1::tl1), Cic.Appl (h2::tl2) when h1 = h2 ->
659                           if cmp tl1 tl2 = Lt then Lt else Incomparable
660                       | _, _ ->  Incomparable
661                   ) else Incomparable
662             | Ge ->
663                 let r = aux t1 t2 in
664                   if r = Gt then Gt
665                   else if r = Eq then (
666                     match t1, t2 with
667                       | Cic.Appl (h1::tl1), Cic.Appl (h2::tl2) when h1 = h2 ->
668                           if cmp tl1 tl2 = Gt then Gt else Incomparable
669                       | _, _ ->  Incomparable
670                   ) else Incomparable
671             | Eq ->
672                 let r = aux t1 t2 in
673                   if r = Eq then (
674                     match t1, t2 with
675                       | Cic.Appl (h1::tl1), Cic.Appl (h2::tl2) when h1 = h2 ->
676                           cmp tl1 tl2
677                       | _, _ ->  Incomparable
678                   ) else r 
679             | res -> res
680 ;;
681
682 let names_of_context context = 
683   List.map
684     (function
685        | None -> None
686        | Some (n, e) -> Some n)
687     context
688 ;;
689
690
691 let rec lpo t1 t2 =
692   let module C = Cic in
693   match t1, t2 with
694   | t1, t2 when t1 = t2 -> Eq
695   | t1, (C.Meta _ as m) ->
696       if TermSet.mem m (metas_of_term t1) then Gt else Incomparable
697   | (C.Meta _ as m), t2 ->
698       if TermSet.mem m (metas_of_term t2) then Lt else Incomparable
699   | C.Appl (hd1::tl1), C.Appl (hd2::tl2) -> (
700       let res =
701         let f o r t =
702           if r then true else
703             match lpo t o with
704             | Gt | Eq -> true
705             | _ -> false
706         in
707         let res1 = List.fold_left (f t2) false tl1 in
708         if res1 then Gt
709         else let res2 = List.fold_left (f t1) false tl2 in
710         if res2 then Lt
711         else Incomparable
712       in
713       if res <> Incomparable then
714         res
715       else
716         let f o r t =
717           if not r then false else
718             match lpo o t with
719             | Gt -> true
720             | _ -> false
721         in
722         match aux_ordering hd1 hd2 with
723         | Gt ->
724             let res = List.fold_left (f t1) false tl2 in
725             if res then Gt
726             else Incomparable
727         | Lt ->
728             let res = List.fold_left (f t2) false tl1 in
729             if res then Lt
730             else Incomparable
731         | Eq -> (
732             let lex_res =
733               try
734                 List.fold_left2
735                   (fun r t1 t2 -> if r <> Eq then r else lpo t1 t2)
736                   Eq tl1 tl2
737               with Invalid_argument _ ->
738                 Incomparable
739             in
740             match lex_res with
741             | Gt ->
742                 if List.fold_left (f t1) false tl2 then Gt
743                 else Incomparable
744             | Lt ->
745                 if List.fold_left (f t2) false tl1 then Lt
746                 else Incomparable
747             | _ -> Incomparable
748           )
749         | _ -> Incomparable
750     )
751   | t1, t2 -> aux_ordering t1 t2
752 ;;
753
754
755 (* settable by the user... *)
756 let compare_terms = ref nonrec_kbo;; 
757 (* let compare_terms = ref ao;; *)
758 (* let compare_terms = ref rpo;; *)
759
760 let guarded_simpl ?(debug=false) context t =
761   if !compare_terms == nonrec_kbo then t
762   else
763     let t' = ProofEngineReduction.simpl context t in
764     if t = t' then t else
765       begin
766         let simpl_order = !compare_terms t t' in
767          debug_print (lazy ("comparing "^(CicPp.ppterm t)^(CicPp.ppterm t')));
768         if simpl_order = Gt then (if debug then prerr_endline "GT";t')
769         else (if debug then prerr_endline "NO_GT";t)
770       end
771 ;;
772
773 type pos = Left | Right 
774
775 let string_of_pos = function
776   | Left -> "Left"
777   | Right -> "Right"
778 ;;
779
780 let metas_of_term t = 
781   List.map fst (CicUtil.metas_of_term t)
782 ;;
783