]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/ocaml/cic_unification/cicMetaSubst.ml
ported debian stuff to ocaml 3.08
[helm.git] / helm / ocaml / cic_unification / cicMetaSubst.ml
index a19bb2b25e405a83b6de8026c0c7b9b2f9795c9d..b594e009ecd08be7e3a627900ea206094acd1855 100644 (file)
+(* Copyright (C) 2003, HELM Team.
+ * 
+ * This file is part of HELM, an Hypertextual, Electronic
+ * Library of Mathematics, developed at the Computer Science
+ * Department, University of Bologna, Italy.
+ * 
+ * HELM is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * HELM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HELM; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ * 
+ * For details, see the HELM World-Wide-Web page,
+ * http://cs.unibo.it/helm/.
+ *)
 
 open Printf
 
-exception AssertFailure of string
+(*  (* PROFILING *)
+let apply_subst_counter = ref 0
+let apply_subst_context_counter = ref 0
+let apply_subst_metasenv_counter = ref 0
+let lift_counter = ref 0
+let subst_counter = ref 0
+let whd_counter = ref 0
+let are_convertible_counter = ref 0
+let metasenv_length = ref 0
+let context_length = ref 0
+let reset_counters () =
+ apply_subst_counter := 0;
+ apply_subst_context_counter := 0;
+ apply_subst_metasenv_counter := 0;
+ lift_counter := 0;
+ subst_counter := 0;
+ whd_counter := 0;
+ are_convertible_counter := 0;
+ metasenv_length := 0;
+ context_length := 0
+let print_counters () =
+  prerr_endline (Printf.sprintf
+"apply_subst: %d
+apply_subst_context: %d
+apply_subst_metasenv: %d
+lift: %d
+subst: %d
+whd: %d
+are_convertible: %d
+metasenv length: %d (avg = %.2f)
+context length: %d (avg = %.2f)
+"
+  !apply_subst_counter !apply_subst_context_counter
+  !apply_subst_metasenv_counter !lift_counter !subst_counter !whd_counter
+  !are_convertible_counter !metasenv_length
+  ((float !metasenv_length) /. (float !apply_subst_metasenv_counter))
+  !context_length
+  ((float !context_length) /. (float !apply_subst_context_counter))
+  )
+*)
+
 exception MetaSubstFailure of string
+exception Uncertain of string
+exception AssertFailure of string
+exception SubstNotFound of int
 
 let debug_print = prerr_endline
 
-type substitution = (int * Cic.term) list
+type substitution = (int * (Cic.context * Cic.term)) list
+
+let lookup_subst n subst =
+  try
+    List.assoc n subst
+  with Not_found -> raise (SubstNotFound n)
+
+(* clean_up_meta take a metasenv and a term and make every local context
+of each occurrence of a metavariable consistent with its canonical context, 
+with respect to the hidden hipothesis *)
+(*
+let clean_up_meta subst metasenv t =
+  let module C = Cic in
+  let rec aux t =
+  match t with
+      C.Rel _
+    | C.Sort _  -> t
+    | C.Implicit _ -> assert false
+    | C.Meta (n,l) as t ->
+        let cc =
+         (try
+            let (cc,_) = lookup_subst n subst in cc
+          with SubstNotFound _ ->
+            try
+              let (_,cc,_) = CicUtil.lookup_meta n metasenv in cc
+             with CicUtil.Meta_not_found _ -> assert false) in
+       let l' = 
+          (try 
+            List.map2
+              (fun t1 t2 ->
+                 match t1,t2 with 
+                     None , _ -> None
+                   | _ , t -> t) cc l
+          with 
+              Invalid_argument _ -> assert false) in
+        C.Meta (n, l')
+    | C.Cast (te,ty) -> C.Cast (aux te, aux ty)
+    | C.Prod (name,so,dest) -> C.Prod (name, aux so, aux dest)
+    | C.Lambda (name,so,dest) -> C.Lambda (name, aux so, aux dest)
+    | C.LetIn (name,so,dest) -> C.LetIn (name, aux so, aux dest)
+    | C.Appl l -> C.Appl (List.map aux l)
+    | C.Var (uri,exp_named_subst) ->
+        let exp_named_subst' =
+          List.map (fun (uri,t) -> (uri, aux t)) exp_named_subst
+        in
+        C.Var (uri, exp_named_subst')
+    | C.Const (uri, exp_named_subst) ->
+        let exp_named_subst' =
+          List.map (fun (uri,t) -> (uri, aux t)) exp_named_subst
+        in
+        C.Const (uri, exp_named_subst')
+    | C.MutInd (uri,tyno,exp_named_subst) ->
+        let exp_named_subst' =
+          List.map (fun (uri,t) -> (uri, aux t)) exp_named_subst
+        in
+        C.MutInd (uri, tyno, exp_named_subst')
+    | C.MutConstruct (uri,tyno,consno,exp_named_subst) ->
+        let exp_named_subst' =
+          List.map (fun (uri,t) -> (uri, aux t)) exp_named_subst
+        in
+        C.MutConstruct (uri, tyno, consno, exp_named_subst')
+    | C.MutCase (uri,tyno,out,te,pl) ->
+        C.MutCase (uri, tyno, aux out, aux te, List.map aux pl)
+    | C.Fix (i,fl) ->
+       let fl' =
+         List.map
+          (fun (name,j,ty,bo) -> (name, j, aux ty, aux bo)) fl
+       in
+       C.Fix (i, fl')
+    | C.CoFix (i,fl) ->
+       let fl' =
+         List.map
+          (fun (name,ty,bo) -> (name, aux ty, aux bo)) fl
+       in
+       C.CoFix (i, fl')
+ in
+ aux t *)
 
 (*** Functions to apply a substitution ***)
 
@@ -16,12 +159,16 @@ let apply_subst_gen ~appl_fun subst term =
   let module S = CicSubstitution in 
    function
       C.Rel _ as t -> t
-    | C.Var _  as t -> t
+    | C.Var (uri,exp_named_subst) ->
+       let exp_named_subst' =
+         List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
+       in
+       C.Var (uri, exp_named_subst')
     | C.Meta (i, l) -> 
         (try
-          let t = List.assoc i subst in
+          let (context, t) = lookup_subst i subst in
           um_aux (S.lift_meta l t)
-        with Not_found -> (* not constrained variable, i.e. free in subst*)
+        with SubstNotFound _ -> (* unconstrained variable, i.e. free in subst*)
           let l' =
             List.map (function None -> None | Some t -> Some (um_aux t)) l
           in
@@ -67,6 +214,7 @@ let apply_subst_gen ~appl_fun subst term =
 ;;
 
 let apply_subst =
+(* CSC: old code that never performs beta reduction
   let appl_fun um_aux he tl =
     let tl' = List.map um_aux tl in
       begin
@@ -76,19 +224,7 @@ let apply_subst =
       end
   in
   apply_subst_gen ~appl_fun
-;;
-
-(* apply_subst_reducing subst (Some (mtr,reductions_no)) t              *)
-(* performs as (apply_subst subst t) until it finds an application of   *)
-(* (META [meta_to_reduce]) that, once unwinding is performed, creates   *)
-(* a new beta-redex; in this case up to [reductions_no] consecutive     *)
-(* beta-reductions are performed.                                       *)
-(* Hint: this function is usually called when [reductions_no]           *)
-(*  eta-expansions have been performed and the head of the new          *)
-(*  application has been unified with (META [meta_to_reduce]):          *)
-(*  during the unwinding the eta-expansions are undone.                 *)
-
-let apply_subst_reducing meta_to_reduce =
+*)
   let appl_fun um_aux he tl =
     let tl' = List.map um_aux tl in
     let t' =
@@ -97,25 +233,32 @@ let apply_subst_reducing meta_to_reduce =
       | he' -> Cic.Appl (he'::tl')
     in
      begin
-      match meta_to_reduce, he with
-         Some (mtr,reductions_no), Cic.Meta (m,_) when m = mtr ->
+      match he with
+         Cic.Meta (m,_) ->
           let rec beta_reduce =
            function
-              (n,(Cic.Appl (Cic.Lambda (_,_,t)::he'::tl'))) when n > 0 ->
+              (Cic.Appl (Cic.Lambda (_,_,t)::he'::tl')) ->
                 let he'' = CicSubstitution.subst he' t in
                  if tl' = [] then
                   he''
                  else
-                  beta_reduce (n-1,Cic.Appl(he''::tl'))
-            | (_,t) -> t
+                  beta_reduce (Cic.Appl(he''::tl'))
+            | t -> t
           in
-           beta_reduce (reductions_no,t')
-       | _,_ -> t'
+           beta_reduce t'
+       | _ -> t'
      end
   in
-  apply_subst_gen ~appl_fun
+  fun s t ->
+(*     incr apply_subst_counter; *)
+    apply_subst_gen ~appl_fun s t
+;;
 
 let rec apply_subst_context subst context =
+(*
+  incr apply_subst_context_counter;
+  context_length := !context_length + List.length context;
+*)
   List.fold_right
     (fun item context ->
       match item with
@@ -134,22 +277,19 @@ let rec apply_subst_context subst context =
     context []
 
 let apply_subst_metasenv subst metasenv =
+(*
+  incr apply_subst_metasenv_counter;
+  metasenv_length := !metasenv_length + List.length metasenv;
+*)
   List.map
     (fun (n, context, ty) ->
       (n, apply_subst_context subst context, apply_subst subst ty))
     (List.filter
-      (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
+      (fun (i, _, _) -> not (List.mem_assoc i subst))
       metasenv)
 
 (***** Pretty printing functions ******)
 
-let ppsubst subst =
-  String.concat "\n"
-    (List.map
-      (fun (idx, term) -> Printf.sprintf "?%d := %s" idx (CicPp.ppterm term))
-      subst)
-;;
-
 let ppterm subst term = CicPp.ppterm (apply_subst subst term)
 
 let ppterm_in_context subst term name_context =
@@ -173,6 +313,29 @@ let ppcontext' ?(sep = "\n") subst context =
           sprintf "%s_ :? _" (separate i), None::name_context
     ) context ("",[])
 
+let ppsubst_unfolded subst =
+  String.concat "\n"
+    (List.map
+      (fun (idx, (c, t)) ->
+        let context,name_context = ppcontext' ~sep:"; " subst c in
+         sprintf "%s |- ?%d:= %s" context idx
+          (ppterm_in_context subst t name_context))
+       subst)
+(* 
+        Printf.sprintf "?%d := %s" idx (CicPp.ppterm term))
+      subst) *)
+;;
+
+let ppsubst subst =
+  String.concat "\n"
+    (List.map
+      (fun (idx, (c, t)) ->
+        let context,name_context = ppcontext' ~sep:"; " [] c in
+         sprintf "%s |- ?%d:= %s" context idx
+          (ppterm_in_context [] t name_context))
+       subst)
+;;
+
 let ppcontext ?sep subst context = fst (ppcontext' ?sep subst context)
 
 let ppmetasenv ?(sep = "\n") metasenv subst =
@@ -183,13 +346,14 @@ let ppmetasenv ?(sep = "\n") metasenv subst =
          sprintf "%s |- ?%d: %s" context i
           (ppterm_in_context subst t name_context))
       (List.filter
-        (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
+        (fun (i, _, _) -> not (List.mem_assoc i subst))
         metasenv))
 
 (* From now on we recreate a kernel abstraction where substitutions are part of
  * the calculus *)
 
 let lift subst n term =
+(*   incr subst_counter; *)
   let term = apply_subst subst term in
   try
     CicSubstitution.lift n term
@@ -197,6 +361,7 @@ let lift subst n term =
     raise (MetaSubstFailure ("Lift failure: " ^ Printexc.to_string e))
 
 let subst subst t1 t2 =
+(*   incr subst_counter; *)
   let t1 = apply_subst subst t1 in
   let t2 = apply_subst subst t2 in
   try
@@ -205,6 +370,7 @@ let subst subst t1 t2 =
     raise (MetaSubstFailure ("Subst failure: " ^ Printexc.to_string e))
 
 let whd subst context term =
+(*   incr whd_counter; *)
   let term = apply_subst subst term in
   let context = apply_subst_context subst context in
   try
@@ -214,36 +380,35 @@ let whd subst context term =
       Printexc.to_string e))
 
 let are_convertible subst context t1 t2 =
+(*   incr are_convertible_counter; *)
   let context = apply_subst_context subst context in
   let t1 = apply_subst subst t1 in
   let t2 = apply_subst subst t2 in
   CicReduction.are_convertible context t1 t2
 
 let tempi_type_of_aux_subst = ref 0.0;;
+let tempi_subst = ref 0.0;;
 let tempi_type_of_aux = ref 0.0;;
 
+  (* assumption: metasenv is already instantiated wrt subst *)
 let type_of_aux' metasenv subst context term =
-let time1 = Unix.gettimeofday () in
+  let time1 = Unix.gettimeofday () in
+(* let term = clean_up_meta subst metasenv term in *)
   let term = apply_subst subst term in
   let context = apply_subst_context subst context in
-  let metasenv =
-    List.map
-      (fun (i, c, t) -> (i, apply_subst_context subst c, apply_subst subst t))
-      (List.filter
-        (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
-        metasenv)
+(*   let metasenv = apply_subst_metasenv subst metasenv in *)
+  let time2 = Unix.gettimeofday () in
+  let res =
+    try
+      CicTypeChecker.type_of_aux' metasenv context term
+    with CicTypeChecker.TypeCheckerFailure msg ->
+      raise (MetaSubstFailure ("Type checker failure: " ^ msg))
   in
-let time2 = Unix.gettimeofday () in
-let res =
-  try
-    CicTypeChecker.type_of_aux' metasenv context term
-  with CicTypeChecker.TypeCheckerFailure msg ->
-    raise (MetaSubstFailure ("Type checker failure: " ^ msg))
-in
-let time3 = Unix.gettimeofday () in
- tempi_type_of_aux_subst := !tempi_type_of_aux_subst +. time3 -. time1 ; 
- tempi_type_of_aux := !tempi_type_of_aux +. time2 -. time1 ; 
- res
+  let time3 = Unix.gettimeofday () in
+   tempi_type_of_aux_subst := !tempi_type_of_aux_subst +. time3 -. time1 ; 
+   tempi_subst := !tempi_subst +. time2 -. time1 ; 
+   tempi_type_of_aux := !tempi_type_of_aux +. time3 -. time2 ; 
+   res
 
 (**** DELIFT ****)
 (* the delift function takes in input a metavariable index, an ordered list of
@@ -353,7 +518,7 @@ let rec restrict subst to_be_restricted metasenv =
       (List.map
         (fun i ->
           try
-           match List.nth context i with
+           match List.nth context (i-1) with
            | None -> assert false
            | Some (n, _) -> CicPp.ppname n
           with
@@ -411,9 +576,9 @@ let rec restrict subst to_be_restricted metasenv =
           with Occur ->
             more_to_be_restricted, (i :: restricted), None :: tl')
   in
-  let (more_to_be_restricted, metasenv, subst) =
+  let (more_to_be_restricted, metasenv) =  (* restrict metasenv *)
     List.fold_right
-      (fun (n, context, t) (more, metasenv, subst) ->
+      (fun (n, context, t) (more, metasenv) ->
         let to_be_restricted =
           List.map snd (List.filter (fun (m, _) -> m = n) to_be_restricted)
         in
@@ -429,37 +594,63 @@ let rec restrict subst to_be_restricted metasenv =
             force_does_not_occur subst restricted t
           in
           let metasenv' = (n, context', t') :: metasenv in
-          (try
-            let s = List.assoc n subst in
-            try
-              let more_to_be_restricted'', s' =
-                force_does_not_occur subst restricted s
-              in
-              let subst' = (n, s') :: (List.remove_assoc n subst) in
-              let more =
-                more @ more_to_be_restricted @ more_to_be_restricted' @
-                  more_to_be_restricted''
-              in
-              (more, metasenv', subst')
-            with Occur ->
-              raise (MetaSubstFailure (sprintf
-                "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since ?%d is already instantiated with %s and at least one of the hypotheses occurs in the substituted term"
-                n (names_of_context_indexes context to_be_restricted) n
-                (ppterm subst s)))
-           with Not_found -> (more @ more_to_be_restricted @ more_to_be_restricted', metasenv', subst))
+          (more @ more_to_be_restricted @ more_to_be_restricted',
+          metasenv')
         with Occur ->
           raise (MetaSubstFailure (sprintf
             "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since metavariable's type depends on at least one of them"
-            n (names_of_context_indexes context to_be_restricted))))
-      metasenv ([], [], subst)
+           n (names_of_context_indexes context to_be_restricted)))) 
+      metasenv ([], [])
+  in
+  let (more_to_be_restricted', subst) = (* restrict subst *)
+    List.fold_right
+      (fun (n, (context, term)) (more, subst') ->
+        let to_be_restricted =
+          List.map snd (List.filter (fun (m, _) -> m = n) to_be_restricted)
+        in
+        (try
+          let (more_to_be_restricted, restricted, context') =
+           (* just an optimization *)
+            if to_be_restricted = [] then
+              [], [], context
+            else
+              erase 1 to_be_restricted n context
+          in
+          let more_to_be_restricted', term' =
+            force_does_not_occur subst restricted term
+          in
+          let subst' = (n, (context', term')) :: subst' in
+          let more = more @ more_to_be_restricted @ more_to_be_restricted' in
+          (more, subst')
+        with Occur ->
+          let error_msg = sprintf
+            "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since ?%d is already instantiated with %s and at least one of the hypotheses occurs in the substituted term"
+            n (names_of_context_indexes context to_be_restricted) n
+            (ppterm subst term)
+         in
+          (* DEBUG
+          prerr_endline error_msg;
+          prerr_endline ("metasenv = \n" ^ (ppmetasenv metasenv subst));
+          prerr_endline ("subst = \n" ^ (ppsubst subst)); 
+          prerr_endline ("context = \n" ^ (ppcontext subst context)); *)
+          raise (MetaSubstFailure error_msg))) 
+      subst ([], [])
   in
-  match more_to_be_restricted with
+  match more_to_be_restricted @ more_to_be_restricted' with
   | [] -> (metasenv, subst)
-  | _ -> restrict subst more_to_be_restricted metasenv
+  | l -> restrict subst l metasenv
 ;;
 
-(*CSC: maybe we should rename delift in abstract, as I did in my dissertation *)
+(*CSC: maybe we should rename delift in abstract, as I did in my dissertation *)(*Andrea: maybe not*)
+
 let delift n subst context metasenv l t =
+(* INVARIANT: we suppose that t is not another occurrence of Meta(n,_), 
+   otherwise the occur check does not make sense *)
+(*
+ prerr_endline ("sto deliftando il termine " ^ (CicPp.ppterm t) ^ " rispetto
+ al contesto locale " ^ (CicPp.ppterm (Cic.Meta(0,l)))); 
+*)
+
  let module S = CicSubstitution in
   let l =
    let (_, canonical_context, _) = CicUtil.lookup_meta n metasenv in
@@ -479,25 +670,32 @@ let delift n subst context metasenv l t =
                     (*CSC: deliftato la regola per il LetIn                 *)
                     (*CSC: FALSO! La regola per il LetIn non lo fa          *)
          else
-          (match List.nth context (m-k-1) with
-            Some (_,C.Def (t,_)) ->
-             (*CSC: Hmmm. This bit of reduction is not in the spirit of    *)
-             (*CSC: first order unification. Does it help or does it harm? *)
-             deliftaux k (S.lift m t)
-          | Some (_,C.Decl t) ->
-             C.Rel ((position (m-k) l) + k)
-          | None -> raise (MetaSubstFailure "RelToHiddenHypothesis"))
+          (try
+            match List.nth context (m-k-1) with
+               Some (_,C.Def (t,_)) ->
+                (*CSC: Hmmm. This bit of reduction is not in the spirit of    *)
+                (*CSC: first order unification. Does it help or does it harm? *)
+                deliftaux k (S.lift m t)
+             | Some (_,C.Decl t) ->
+                C.Rel ((position (m-k) l) + k)
+             | None -> raise (MetaSubstFailure "RelToHiddenHypothesis")
+           with
+            Failure _ ->
+             raise (MetaSubstFailure "Unbound variable found in deliftaux")
+          )
      | C.Var (uri,exp_named_subst) ->
         let exp_named_subst' =
          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
         in
          C.Var (uri,exp_named_subst')
      | C.Meta (i, l1) as t -> 
-        if i = n then
+         (* see the top level invariant *)
+        if (i = n) then 
           raise (MetaSubstFailure (sprintf
             "Cannot unify the metavariable ?%d with a term that has as subterm %s in which the same metavariable occurs (occur check)"
-            i (ppterm subst t)))
+            i (ppterm subst t))) 
         else
+         begin
          (* I do not consider the term associated to ?i in subst since *)
          (* in this way I can restrict if something goes wrong.        *)
           let rec deliftl j =
@@ -511,10 +709,11 @@ let delift n subst context metasenv l t =
                 with
                    NotInTheList
                  | MetaSubstFailure _ ->
-                    to_be_restricted := (i,j)::!to_be_restricted ; None::l1'
+                    to_be_restricted := (i,j)::!to_be_restricted ; None::l1'
           in
-           let l' = deliftl 1 l1 in
-            C.Meta(i,l')
+            let l' = deliftl 1 l1 in
+              C.Meta(i,l')
+        end
      | C.Sort _ as t -> t
      | C.Implicit _ as t -> t
      | C.Cast (te,ty) -> C.Cast (deliftaux k te, deliftaux k ty)
@@ -567,8 +766,15 @@ let delift n subst context metasenv l t =
       (* The reason is that our delift function is weaker than first  *)
       (* order (in the sense of alpha-conversion). See comment above  *)
       (* related to the delift function.                              *)
-debug_print "!!!!!!!!!!! First Order UnificationFailure, but maybe it could have been successful even in a first order setting (no conversion, only alpha convertibility)! Please, implement a better delift function !!!!!!!!!!!!!!!!" ;
-      raise (MetaSubstFailure (sprintf
+(* debug_print "First Order UnificationFailure during delift" ;
+prerr_endline(sprintf
+        "Error trying to abstract %s over [%s]: the algorithm only tried to abstract over bound variables"
+        (ppterm subst t)
+        (String.concat "; "
+          (List.map
+            (function Some t -> ppterm subst t | None -> "_") l
+          ))); *)
+      raise (Uncertain (sprintf
         "Error trying to abstract %s over [%s]: the algorithm only tried to abstract over bound variables"
         (ppterm subst t)
         (String.concat "; "