X-Git-Url: http://matita.cs.unibo.it/gitweb/?a=blobdiff_plain;f=helm%2Focaml%2Fcic_unification%2FcicMetaSubst.ml;h=718951c68a579756e4c4bd1d0994c835d28e2bac;hb=4167cea65ca58897d1a3dbb81ff95de5074700cc;hp=04cf03c67b81f4b70eafd229694b71ffec9b162d;hpb=cc3d3e3f697e06026680bc94988c782ddd8eb33e;p=helm.git diff --git a/helm/ocaml/cic_unification/cicMetaSubst.ml b/helm/ocaml/cic_unification/cicMetaSubst.ml index 04cf03c67..718951c68 100644 --- a/helm/ocaml/cic_unification/cicMetaSubst.ml +++ b/helm/ocaml/cic_unification/cicMetaSubst.ml @@ -1,32 +1,374 @@ +(* 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 -exception MetaSubstFailure of string -exception RelToHiddenHypothesis +(* PROFILING *) +(* +let deref_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 () = + debug_print (lazy (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)) + ))*) -let debug_print = prerr_endline -type substitution = (int * Cic.term) list + +exception MetaSubstFailure of string Lazy.t +exception Uncertain of string Lazy.t +exception AssertFailure of string Lazy.t +exception DeliftingARelWouldCaptureAFreeVariable;; + +let debug_print = fun _ -> () + +type substitution = (int * (Cic.context * Cic.term)) list + +(* +let rec deref subst = + let third _,_,a = a in + function + Cic.Meta(n,l) as t -> + (try + deref subst + (CicSubstitution.subst_meta + l (third (CicUtil.lookup_subst n subst))) + with + CicUtil.Subst_not_found _ -> t) + | t -> t +;; +*) + +let lookup_subst = CicUtil.lookup_subst +;; + + +(* 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 CicUtil.Subst_not_found _ -> + 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 ***) + +let apply_subst_gen ~appl_fun subst term = + let rec um_aux = + let module C = Cic in + let module S = CicSubstitution in + function + C.Rel _ 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,_) = lookup_subst i subst in + um_aux (S.subst_meta l t) + with CicUtil.Subst_not_found _ -> + (* unconstrained variable, i.e. free in subst*) + let l' = + List.map (function None -> None | Some t -> Some (um_aux t)) l + in + C.Meta (i,l')) + | C.Sort _ + | C.Implicit _ as t -> t + | C.Cast (te,ty) -> C.Cast (um_aux te, um_aux ty) + | C.Prod (n,s,t) -> C.Prod (n, um_aux s, um_aux t) + | C.Lambda (n,s,t) -> C.Lambda (n, um_aux s, um_aux t) + | C.LetIn (n,s,t) -> C.LetIn (n, um_aux s, um_aux t) + | C.Appl (hd :: tl) -> appl_fun um_aux hd tl + | C.Appl _ -> assert false + | C.Const (uri,exp_named_subst) -> + let exp_named_subst' = + List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst + in + C.Const (uri, exp_named_subst') + | C.MutInd (uri,typeno,exp_named_subst) -> + let exp_named_subst' = + List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst + in + C.MutInd (uri,typeno,exp_named_subst') + | C.MutConstruct (uri,typeno,consno,exp_named_subst) -> + let exp_named_subst' = + List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst + in + C.MutConstruct (uri,typeno,consno,exp_named_subst') + | C.MutCase (sp,i,outty,t,pl) -> + let pl' = List.map um_aux pl in + C.MutCase (sp, i, um_aux outty, um_aux t, pl') + | C.Fix (i, fl) -> + let fl' = + List.map (fun (name, i, ty, bo) -> (name, i, um_aux ty, um_aux bo)) fl + in + C.Fix (i, fl') + | C.CoFix (i, fl) -> + let fl' = + List.map (fun (name, ty, bo) -> (name, um_aux ty, um_aux bo)) fl + in + C.CoFix (i, fl') + in + um_aux term +;; + +let apply_subst = + let appl_fun um_aux he tl = + let tl' = List.map um_aux tl in + let t' = + match um_aux he with + Cic.Appl l -> Cic.Appl (l@tl') + | he' -> Cic.Appl (he'::tl') + in + begin + match he with + Cic.Meta (m,_) -> CicReduction.head_beta_reduce t' + | _ -> t' + end + in + 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 + | Some (n, Cic.Decl t) -> + let t' = apply_subst subst t in + Some (n, Cic.Decl t') :: context + | Some (n, Cic.Def (t, ty)) -> + let ty' = + match ty with + | None -> None + | Some ty -> Some (apply_subst subst ty) + in + let t' = apply_subst subst t in + Some (n, Cic.Def (t', ty')) :: context + | None -> None :: 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.mem_assoc i subst)) + metasenv) + +(***** Pretty printing functions ******) + +let ppterm subst term = CicPp.ppterm (apply_subst subst term) + +let ppterm_in_name_context subst term name_context = + CicPp.pp (apply_subst subst term) name_context + +let ppterm_in_context subst term context = + let name_context = + List.map (function None -> None | Some (n,_) -> Some n) context + in + ppterm_in_name_context subst term name_context + +let ppcontext' ?(sep = "\n") subst context = + let separate s = if s = "" then "" else s ^ sep in + List.fold_right + (fun context_entry (i,name_context) -> + match context_entry with + Some (n,Cic.Decl t) -> + sprintf "%s%s : %s" (separate i) (CicPp.ppname n) + (ppterm_in_name_context subst t name_context), (Some n)::name_context + | Some (n,Cic.Def (bo,ty)) -> + sprintf "%s%s : %s := %s" (separate i) (CicPp.ppname n) + (match ty with + None -> "_" + | Some ty -> ppterm_in_name_context subst ty name_context) + (ppterm_in_name_context subst bo name_context), (Some n)::name_context + | None -> + 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_name_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, term) -> Printf.sprintf "?%d := %s" idx (CicPp.ppterm term)) - subst) + (fun (idx, (c, t, _)) -> + let context,name_context = ppcontext' ~sep:"; " [] c in + sprintf "%s |- ?%d:= %s" context idx + (ppterm_in_name_context [] t name_context)) + subst) +;; -(**** DELIFT ****) +let ppcontext ?sep subst context = fst (ppcontext' ?sep subst context) -(* the delift function takes in input an ordered list of optional terms *) -(* [t1,...,tn] and a term t, and substitutes every tk = Some (rel(nk)) with *) -(* rel(k). Typically, the list of optional terms is the explicit substitution *) -(* that is applied to a metavariable occurrence and the result of the delift *) -(* function is a term the implicit variable can be substituted with to make *) -(* the term [t] unifiable with the metavariable occurrence. *) -(* In general, the problem is undecidable if we consider equivalence in place *) -(* of alpha convertibility. Our implementation, though, is even weaker than *) -(* alpha convertibility, since it replace the term [tk] if and only if [tk] *) -(* is a Rel (missing all the other cases). Does this matter in practice? *) +let ppmetasenv ?(sep = "\n") subst metasenv = + String.concat sep + (List.map + (fun (i, c, t) -> + let context,name_context = ppcontext' ~sep:"; " subst c in + sprintf "%s |- ?%d: %s" context i + (ppterm_in_name_context subst t name_context)) + (List.filter + (fun (i, _, _) -> not (List.mem_assoc i subst)) + metasenv)) + +let tempi_type_of_aux_subst = ref 0.0;; +let tempi_subst = ref 0.0;; +let tempi_type_of_aux = ref 0.0;; + +(**** DELIFT ****) +(* the delift function takes in input a metavariable index, an ordered list of + * optional terms [t1,...,tn] and a term t, and substitutes every tk = Some + * (rel(nk)) with rel(k). Typically, the list of optional terms is the explicit + * substitution that is applied to a metavariable occurrence and the result of + * the delift function is a term the implicit variable can be substituted with + * to make the term [t] unifiable with the metavariable occurrence. In general, + * the problem is undecidable if we consider equivalence in place of alpha + * convertibility. Our implementation, though, is even weaker than alpha + * convertibility, since it replace the term [tk] if and only if [tk] is a Rel + * (missing all the other cases). Does this matter in practice? + * The metavariable index is the index of the metavariable that must not occur + * in the term (for occur check). + *) exception NotInTheList;; @@ -38,30 +380,237 @@ let position n = | _::tl -> aux (k+1) tl in aux 1 ;; + +exception Occur;; + +let rec force_does_not_occur subst to_be_restricted t = + let module C = Cic in + let more_to_be_restricted = ref [] in + let rec aux k = function + C.Rel r when List.mem (r - k) to_be_restricted -> raise Occur + | C.Rel _ + | C.Sort _ as t -> t + | C.Implicit _ -> assert false + | C.Meta (n, l) -> + (* we do not retrieve the term associated to ?n in subst since *) + (* in this way we can restrict if something goes wrong *) + let l' = + let i = ref 0 in + List.map + (function t -> + incr i ; + match t with + None -> None + | Some t -> + try + Some (aux k t) + with Occur -> + more_to_be_restricted := (n,!i) :: !more_to_be_restricted; + None) + l + in + C.Meta (n, l') + | C.Cast (te,ty) -> C.Cast (aux k te, aux k ty) + | C.Prod (name,so,dest) -> C.Prod (name, aux k so, aux (k+1) dest) + | C.Lambda (name,so,dest) -> C.Lambda (name, aux k so, aux (k+1) dest) + | C.LetIn (name,so,dest) -> C.LetIn (name, aux k so, aux (k+1) dest) + | C.Appl l -> C.Appl (List.map (aux k) l) + | C.Var (uri,exp_named_subst) -> + let exp_named_subst' = + List.map (fun (uri,t) -> (uri, aux k 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 k 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 k 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 k 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 k out, aux k te, List.map (aux k) pl) + | C.Fix (i,fl) -> + let len = List.length fl in + let k_plus_len = k + len in + let fl' = + List.map + (fun (name,j,ty,bo) -> (name, j, aux k ty, aux k_plus_len bo)) fl + in + C.Fix (i, fl') + | C.CoFix (i,fl) -> + let len = List.length fl in + let k_plus_len = k + len in + let fl' = + List.map + (fun (name,ty,bo) -> (name, aux k ty, aux k_plus_len bo)) fl + in + C.CoFix (i, fl') + in + let res = aux 0 t in + (!more_to_be_restricted, res) -(*CSC: this restriction function is utterly wrong, since it does not check *) -(*CSC: that the variable that is going to be restricted does not occur free *) -(*CSC: in a part of the sequent that is not going to be restricted. *) -(*CSC: In particular, the whole approach is wrong; if restriction can fail *) -(*CSC: (as indeed it is the case), we can not collect all the restrictions *) -(*CSC: and restrict everything at the end ;-( *) -let restrict to_be_restricted = - let rec erase i n = - function - [] -> [] - | _::tl when List.mem (n,i) to_be_restricted -> - None::(erase (i+1) n tl) - | he::tl -> he::(erase (i+1) n tl) in - let rec aux = - function - [] -> [] - | (n,context,t)::tl -> (n,erase 1 n context,t)::(aux tl) in - aux +let rec restrict subst to_be_restricted metasenv = + let names_of_context_indexes context indexes = + String.concat ", " + (List.map + (fun i -> + try + match List.nth context (i-1) with + | None -> assert false + | Some (n, _) -> CicPp.ppname n + with + Failure _ -> assert false + ) indexes) + in + let force_does_not_occur_in_context to_be_restricted = function + | None -> [], None + | Some (name, Cic.Decl t) -> + let (more_to_be_restricted, t') = + force_does_not_occur subst to_be_restricted t + in + more_to_be_restricted, Some (name, Cic.Decl t') + | Some (name, Cic.Def (bo, ty)) -> + let (more_to_be_restricted, bo') = + force_does_not_occur subst to_be_restricted bo + in + let more_to_be_restricted, ty' = + match ty with + | None -> more_to_be_restricted, None + | Some ty -> + let more_to_be_restricted', ty' = + force_does_not_occur subst to_be_restricted ty + in + more_to_be_restricted @ more_to_be_restricted', + Some ty' + in + more_to_be_restricted, Some (name, Cic.Def (bo', ty')) + in + let rec erase i to_be_restricted n = function + | [] -> [], to_be_restricted, [] + | hd::tl -> + let more_to_be_restricted,restricted,tl' = + erase (i+1) to_be_restricted n tl + in + let restrict_me = List.mem i restricted in + if restrict_me then + more_to_be_restricted, restricted, None:: tl' + else + (try + let more_to_be_restricted', hd' = + let delifted_restricted = + let rec aux = + function + [] -> [] + | j::tl when j > i -> (j - i)::aux tl + | _::tl -> aux tl + in + aux restricted + in + force_does_not_occur_in_context delifted_restricted hd + in + more_to_be_restricted @ more_to_be_restricted', + restricted, hd' :: tl' + with Occur -> + more_to_be_restricted, (i :: restricted), None :: tl') + in + let (more_to_be_restricted, metasenv) = (* restrict metasenv *) + List.fold_right + (fun (n, context, t) (more, metasenv) -> + let to_be_restricted = + List.map snd (List.filter (fun (m, _) -> m = n) to_be_restricted) + in + 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 + try + let more_to_be_restricted', t' = + force_does_not_occur subst restricted t + in + let metasenv' = (n, context', t') :: metasenv in + (more @ more_to_be_restricted @ more_to_be_restricted', + metasenv') + with Occur -> + raise (MetaSubstFailure (lazy (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 ([], []) + in + let (more_to_be_restricted', subst) = (* restrict subst *) + List.fold_right + (* TODO: cambiare dopo l'aggiunta del ty *) + (fun (n, (context, term,ty)) (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 more_to_be_restricted'', ty' = + force_does_not_occur subst restricted ty in + let subst' = (n, (context', term',ty')) :: subst' in + let more = + more @ more_to_be_restricted + @ more_to_be_restricted'@more_to_be_restricted'' in + (more, subst') + with Occur -> + let error_msg = lazy (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 + debug_print (lazy error_msg); + debug_print (lazy ("metasenv = \n" ^ (ppmetasenv metasenv subst))); + debug_print (lazy ("subst = \n" ^ (ppsubst subst))); + debug_print (lazy ("context = \n" ^ (ppcontext subst context))); *) + raise (MetaSubstFailure error_msg))) + subst ([], []) + in + match more_to_be_restricted @ more_to_be_restricted' with + | [] -> (metasenv, subst) + | l -> restrict subst l metasenv ;; -(*CSC: maybe we should rename delift in abstract, as I did in my dissertation *) -let delift context metasenv l t = +(*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 *) + +(* + debug_print (lazy ("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 + List.map2 (fun ct lt -> + match (ct, lt) with + | None, _ -> None + | Some _, _ -> lt) + canonical_context l + in let to_be_restricted = ref [] in let rec deliftaux k = let module C = Cic in @@ -72,47 +621,57 @@ let delift 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) -> - (*CSC: The following check seems to be wrong! *) - (*CSC: B:Set |- ?2 : Set *) - (*CSC: A:Set ; x:?2[A/B] |- ?1[x/A] =?= x *) - (*CSC: Why should I restrict ?2 over B? The instantiation *) - (*CSC: ?1 := A is perfectly reasonable and well-typed. *) - (*CSC: Thus I comment out the following two lines that *) - (*CSC: are the incriminated ones. *) - (*(* It may augment to_be_restricted *) - ignore (deliftaux k (S.lift m t)) ;*) - (*CSC: end of bug commented out *) - C.Rel ((position (m-k) l) + k) - | None -> raise 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 (lazy "RelToHiddenHypothesis")) + with + Failure _ -> + raise (MetaSubstFailure (lazy "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 -> - let rec deliftl j = - function - [] -> [] - | None::tl -> None::(deliftl (j+1) tl) - | (Some t)::tl -> - let l1' = (deliftl (j+1) tl) in - try - Some (deliftaux k t)::l1' - with - RelToHiddenHypothesis - | NotInTheList -> - to_be_restricted := (i,j)::!to_be_restricted ; None::l1' - in - let l' = deliftl 1 l1 in - C.Meta(i,l') + (try + let (_,t,_) = CicUtil.lookup_subst i subst in + deliftaux k (CicSubstitution.subst_meta l1 t) + with CicUtil.Subst_not_found _ -> + (* see the top level invariant *) + if (i = n) then + raise (MetaSubstFailure (lazy (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)))) + 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 = + function + [] -> [] + | None::tl -> None::(deliftl (j+1) tl) + | (Some t)::tl -> + let l1' = (deliftl (j+1) tl) in + try + Some (deliftaux k t)::l1' + with + NotInTheList + | MetaSubstFailure _ -> + to_be_restricted := + (i,j)::!to_be_restricted ; None::l1' + in + let l' = deliftl 1 l1 in + C.Meta(i,l') + end) | C.Sort _ as t -> t - | C.Implicit as t -> t + | C.Implicit _ as t -> t | C.Cast (te,ty) -> C.Cast (deliftaux k te, deliftaux k ty) | C.Prod (n,s,t) -> C.Prod (n, deliftaux k s, deliftaux (k+1) t) | C.Lambda (n,s,t) -> C.Lambda (n, deliftaux k s, deliftaux (k+1) t) @@ -163,338 +722,175 @@ let delift 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 (lazy "First Order UnificationFailure during delift") ; +debug_print(lazy (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 (lazy (sprintf "Error trying to abstract %s over [%s]: the algorithm only tried to abstract over bound variables" - (CicPp.ppterm t) + (ppterm subst t) (String.concat "; " (List.map - (function Some t -> CicPp.ppterm t | None -> "_") - l)))) + (function Some t -> ppterm subst t | None -> "_") + l))))) in - res, restrict !to_be_restricted metasenv + let (metasenv, subst) = restrict subst !to_be_restricted metasenv in + res, metasenv, subst ;; -(**** END OF DELIFT ****) - -let rec unwind metasenv subst unwinded t = - let unwinded = ref unwinded in - let frozen = ref [] in - let rec um_aux metasenv = +(* delifts a term t of n levels strating from k, that is changes (Rel m) + * to (Rel (m - n)) when m > (k + n). if k <= m < k + n delift fails + *) +let delift_rels_from subst metasenv k n = + let rec liftaux subst metasenv k = let module C = Cic in - let module S = CicSubstitution in function - C.Rel _ as t -> t,metasenv - | C.Var _ as t -> t,metasenv - | C.Meta (i,l) -> + C.Rel m -> + if m < k then + C.Rel m, subst, metasenv + else if m < k + n then + raise DeliftingARelWouldCaptureAFreeVariable + else + C.Rel (m - n), subst, metasenv + | C.Var (uri,exp_named_subst) -> + let exp_named_subst',subst,metasenv = + List.fold_right + (fun (uri,t) (l,subst,metasenv) -> + let t',subst,metasenv = liftaux subst metasenv k t in + (uri,t')::l,subst,metasenv) exp_named_subst ([],subst,metasenv) + in + C.Var (uri,exp_named_subst'),subst,metasenv + | C.Meta (i,l) -> (try - S.lift_meta l (List.assoc i !unwinded), metasenv - with Not_found -> - if List.mem i !frozen then - raise (MetaSubstFailure - "Failed to unify due to cyclic constraints (occur check)") - else - let saved_frozen = !frozen in - frozen := i::!frozen ; - let res = - try - let t = List.assoc i subst in - let t',metasenv' = um_aux metasenv t in - let _,metasenv'' = - let (_,canonical_context,_) = - List.find (function (m,_,_) -> m=i) metasenv - in - delift canonical_context metasenv' l t' - in - unwinded := (i,t')::!unwinded ; - S.lift_meta l t', metasenv' - with - Not_found -> - (* not constrained variable, i.e. free in subst*) - let l',metasenv' = - List.fold_right - (fun t (tl,metasenv) -> - match t with - None -> None::tl,metasenv - | Some t -> - let t',metasenv' = um_aux metasenv t in - (Some t')::tl, metasenv' - ) l ([],metasenv) - in - C.Meta (i,l'), metasenv' - in - frozen := saved_frozen ; - res - ) - | C.Sort _ - | C.Implicit as t -> t,metasenv + let (_, t,_) = lookup_subst i subst in + liftaux subst metasenv k (CicSubstitution.subst_meta l t) + with CicUtil.Subst_not_found _ -> + let l',to_be_restricted,subst,metasenv = + let rec aux con l subst metasenv = + match l with + [] -> [],[],subst,metasenv + | he::tl -> + let tl',to_be_restricted,subst,metasenv = + aux (con + 1) tl subst metasenv in + let he',more_to_be_restricted,subst,metasenv = + match he with + None -> None,[],subst,metasenv + | Some t -> + try + let t',subst,metasenv = liftaux subst metasenv k t in + Some t',[],subst,metasenv + with + DeliftingARelWouldCaptureAFreeVariable -> + None,[i,con],subst,metasenv + in + he'::tl',more_to_be_restricted@to_be_restricted,subst,metasenv + in + aux 1 l subst metasenv in + let metasenv,subst = restrict subst to_be_restricted metasenv in + C.Meta(i,l'),subst,metasenv) + | C.Sort _ as t -> t,subst,metasenv + | C.Implicit _ as t -> t,subst,metasenv | C.Cast (te,ty) -> - let te',metasenv' = um_aux metasenv te in - let ty',metasenv'' = um_aux metasenv' ty in - C.Cast (te',ty'),metasenv'' + let te',subst,metasenv = liftaux subst metasenv k te in + let ty',subst,metasenv = liftaux subst metasenv k ty in + C.Cast (te',ty'),subst,metasenv | C.Prod (n,s,t) -> - let s',metasenv' = um_aux metasenv s in - let t',metasenv'' = um_aux metasenv' t in - C.Prod (n, s', t'), metasenv'' + let s',subst,metasenv = liftaux subst metasenv k s in + let t',subst,metasenv = liftaux subst metasenv (k+1) t in + C.Prod (n,s',t'),subst,metasenv | C.Lambda (n,s,t) -> - let s',metasenv' = um_aux metasenv s in - let t',metasenv'' = um_aux metasenv' t in - C.Lambda (n, s', t'), metasenv'' + let s',subst,metasenv = liftaux subst metasenv k s in + let t',subst,metasenv = liftaux subst metasenv (k+1) t in + C.Lambda (n,s',t'),subst,metasenv | C.LetIn (n,s,t) -> - let s',metasenv' = um_aux metasenv s in - let t',metasenv'' = um_aux metasenv' t in - C.LetIn (n, s', t'), metasenv'' - | C.Appl (he::tl) -> - let tl',metasenv' = + let s',subst,metasenv = liftaux subst metasenv k s in + let t',subst,metasenv = liftaux subst metasenv (k+1) t in + C.LetIn (n,s',t'),subst,metasenv + | C.Appl l -> + let l',subst,metasenv = List.fold_right - (fun t (tl,metasenv) -> - let t',metasenv' = um_aux metasenv t in - t'::tl, metasenv' - ) tl ([],metasenv) - in - begin - match um_aux metasenv' he with - (C.Appl l, metasenv'') -> C.Appl (l@tl'),metasenv'' - | (he', metasenv'') -> C.Appl (he'::tl'),metasenv'' - end - | C.Appl _ -> assert false + (fun t (l,subst,metasenv) -> + let t',subst,metasenv = liftaux subst metasenv k t in + t'::l,subst,metasenv) l ([],subst,metasenv) in + C.Appl l',subst,metasenv | C.Const (uri,exp_named_subst) -> - let exp_named_subst', metasenv' = + let exp_named_subst',subst,metasenv = List.fold_right - (fun (uri,t) (tl,metasenv) -> - let t',metasenv' = um_aux metasenv t in - (uri,t')::tl, metasenv' - ) exp_named_subst ([],metasenv) + (fun (uri,t) (l,subst,metasenv) -> + let t',subst,metasenv = liftaux subst metasenv k t in + (uri,t')::l,subst,metasenv) exp_named_subst ([],subst,metasenv) in - C.Const (uri,exp_named_subst'),metasenv' - | C.MutInd (uri,typeno,exp_named_subst) -> - let exp_named_subst', metasenv' = + C.Const (uri,exp_named_subst'),subst,metasenv + | C.MutInd (uri,tyno,exp_named_subst) -> + let exp_named_subst',subst,metasenv = List.fold_right - (fun (uri,t) (tl,metasenv) -> - let t',metasenv' = um_aux metasenv t in - (uri,t')::tl, metasenv' - ) exp_named_subst ([],metasenv) + (fun (uri,t) (l,subst,metasenv) -> + let t',subst,metasenv = liftaux subst metasenv k t in + (uri,t')::l,subst,metasenv) exp_named_subst ([],subst,metasenv) in - C.MutInd (uri,typeno,exp_named_subst'),metasenv' - | C.MutConstruct (uri,typeno,consno,exp_named_subst) -> - let exp_named_subst', metasenv' = + C.MutInd (uri,tyno,exp_named_subst'),subst,metasenv + | C.MutConstruct (uri,tyno,consno,exp_named_subst) -> + let exp_named_subst',subst,metasenv = List.fold_right - (fun (uri,t) (tl,metasenv) -> - let t',metasenv' = um_aux metasenv t in - (uri,t')::tl, metasenv' - ) exp_named_subst ([],metasenv) + (fun (uri,t) (l,subst,metasenv) -> + let t',subst,metasenv = liftaux subst metasenv k t in + (uri,t')::l,subst,metasenv) exp_named_subst ([],subst,metasenv) in - C.MutConstruct (uri,typeno,consno,exp_named_subst'),metasenv' + C.MutConstruct (uri,tyno,consno,exp_named_subst'),subst,metasenv | C.MutCase (sp,i,outty,t,pl) -> - let outty',metasenv' = um_aux metasenv outty in - let t',metasenv'' = um_aux metasenv' t in - let pl',metasenv''' = + let outty',subst,metasenv = liftaux subst metasenv k outty in + let t',subst,metasenv = liftaux subst metasenv k t in + let pl',subst,metasenv = List.fold_right - (fun p (pl,metasenv) -> - let p',metasenv' = um_aux metasenv p in - p'::pl, metasenv' - ) pl ([],metasenv'') + (fun t (l,subst,metasenv) -> + let t',subst,metasenv = liftaux subst metasenv k t in + t'::l,subst,metasenv) pl ([],subst,metasenv) in - C.MutCase (sp, i, outty', t', pl'),metasenv''' + C.MutCase (sp,i,outty',t',pl'),subst,metasenv | C.Fix (i, fl) -> let len = List.length fl in - let liftedfl,metasenv' = + let liftedfl,subst,metasenv = List.fold_right - (fun (name, i, ty, bo) (fl,metasenv) -> - let ty',metasenv' = um_aux metasenv ty in - let bo',metasenv'' = um_aux metasenv' bo in - (name, i, ty', bo')::fl,metasenv'' - ) fl ([],metasenv) + (fun (name, i, ty, bo) (l,subst,metasenv) -> + let ty',subst,metasenv = liftaux subst metasenv k ty in + let bo',subst,metasenv = liftaux subst metasenv (k+len) bo in + (name,i,ty',bo')::l,subst,metasenv + ) fl ([],subst,metasenv) in - C.Fix (i, liftedfl),metasenv' + C.Fix (i, liftedfl),subst,metasenv | C.CoFix (i, fl) -> let len = List.length fl in - let liftedfl,metasenv' = + let liftedfl,subst,metasenv = List.fold_right - (fun (name, ty, bo) (fl,metasenv) -> - let ty',metasenv' = um_aux metasenv ty in - let bo',metasenv'' = um_aux metasenv' bo in - (name, ty', bo')::fl,metasenv'' - ) fl ([],metasenv) + (fun (name, ty, bo) (l,subst,metasenv) -> + let ty',subst,metasenv = liftaux subst metasenv k ty in + let bo',subst,metasenv = liftaux subst metasenv (k+len) bo in + (name,ty',bo')::l,subst,metasenv + ) fl ([],subst,metasenv) in - C.CoFix (i, liftedfl),metasenv' + C.CoFix (i, liftedfl),subst,metasenv in - let t',metasenv' = um_aux metasenv t in - t',metasenv',!unwinded - -let apply_subst subst t = - (* metasenv will not be used nor modified. So, let's use a dummy empty one *) - let metasenv = [] in - let (t',_,_) = unwind metasenv [] subst t in - t' - -(* 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 rec apply_subst_context subst = - List.map (function - | Some (n, Cic.Decl t) -> Some (n, Cic.Decl (apply_subst subst t)) - | Some (n, Cic.Def (t, ty)) -> - let ty' = - match ty with - | None -> None - | Some ty -> Some (apply_subst subst ty) - in - Some (n, Cic.Def (apply_subst subst t, ty')) - | None -> None) + liftaux subst metasenv k -let rec apply_subst_reducing subst meta_to_reduce t = - let rec um_aux = - let module C = Cic in - let module S = CicSubstitution in - function - C.Rel _ - | C.Var _ as t -> t - | C.Meta (i,l) as t -> - (try - S.lift_meta l (List.assoc i subst) - with Not_found -> - C.Meta (i,l)) - | C.Sort _ as t -> t - | C.Implicit as t -> t - | C.Cast (te,ty) -> C.Cast (um_aux te, um_aux ty) - | C.Prod (n,s,t) -> C.Prod (n, um_aux s, um_aux t) - | C.Lambda (n,s,t) -> C.Lambda (n, um_aux s, um_aux t) - | C.LetIn (n,s,t) -> C.LetIn (n, um_aux s, um_aux t) - | C.Appl (he::tl) -> - let tl' = List.map um_aux tl in - let t' = - match um_aux he with - C.Appl l -> C.Appl (l@tl') - | _ as he' -> C.Appl (he'::tl') - in - begin - match meta_to_reduce,he with - Some (mtr,reductions_no), C.Meta (m,_) when m = mtr -> - let rec beta_reduce = - function - (n,(C.Appl (C.Lambda (_,_,t)::he'::tl'))) when n > 0 -> - let he'' = CicSubstitution.subst he' t in - if tl' = [] then - he'' - else - beta_reduce (n-1,C.Appl(he''::tl')) - | (_,t) -> t - in - beta_reduce (reductions_no,t') - | _,_ -> t' - end - | C.Appl _ -> assert false - | C.Const (uri,exp_named_subst) -> - let exp_named_subst' = - List.map (function (uri,t) -> (uri,um_aux t)) exp_named_subst - in - C.Const (uri,exp_named_subst') - | C.MutInd (uri,typeno,exp_named_subst) -> - let exp_named_subst' = - List.map (function (uri,t) -> (uri,um_aux t)) exp_named_subst - in - C.MutInd (uri,typeno,exp_named_subst') - | C.MutConstruct (uri,typeno,consno,exp_named_subst) -> - let exp_named_subst' = - List.map (function (uri,t) -> (uri,um_aux t)) exp_named_subst - in - C.MutConstruct (uri,typeno,consno,exp_named_subst') - | C.MutCase (sp,i,outty,t,pl) -> - C.MutCase (sp, i, um_aux outty, um_aux t, - List.map um_aux pl) - | C.Fix (i, fl) -> - let len = List.length fl in - let liftedfl = - List.map - (fun (name, i, ty, bo) -> (name, i, um_aux ty, um_aux bo)) - fl - in - C.Fix (i, liftedfl) - | C.CoFix (i, fl) -> - let len = List.length fl in - let liftedfl = - List.map - (fun (name, ty, bo) -> (name, um_aux ty, um_aux bo)) - fl - in - C.CoFix (i, liftedfl) - in - um_aux t +let delift_rels subst metasenv n t = + delift_rels_from subst metasenv 1 n t + -let ppcontext ?(sep = "\n") subst context = - String.concat sep - (List.rev_map (function - | Some (n, Cic.Decl t) -> - sprintf "%s : %s" - (CicPp.ppname n) (CicPp.ppterm (apply_subst subst t)) - | Some (n, Cic.Def (t, ty)) -> - sprintf "%s : %s := %s" - (CicPp.ppname n) - (match ty with - | None -> "_" - | Some ty -> CicPp.ppterm (apply_subst subst ty)) - (CicPp.ppterm (apply_subst subst t)) - | None -> "_") - context) +(**** END OF DELIFT ****) -let ppmetasenv ?(sep = "\n") subst metasenv = - String.concat sep - (List.map - (fun (i, c, t) -> - sprintf "%s |- ?%d: %s" (ppcontext ~sep:"; " subst c) i - (CicPp.ppterm (apply_subst subst t))) - (List.filter - (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst)) - metasenv)) -(* UNWIND THE MGU INSIDE THE MGU *) -let unwind_subst metasenv subst = - List.fold_left - (fun (unwinded,metasenv) (i,_) -> - let (_,canonical_context,_) = - List.find (function (m,_,_) -> m=i) metasenv - in - let identity_relocation_list = - CicMkImplicit.identity_relocation_list_for_metavariable canonical_context - in - let (_,metasenv',subst') = - unwind metasenv subst unwinded (Cic.Meta (i,identity_relocation_list)) - in - subst',metasenv' - ) ([],metasenv) subst - -(* From now on we recreate a kernel abstraction where substitutions are part of - * the calculus *) - -let whd subst context term = - let term = apply_subst subst term in - let context = apply_subst_context subst context in - try - CicReduction.whd context term - with e -> - raise (MetaSubstFailure ("Weak head reduction failure: " ^ - Printexc.to_string e)) - -let type_of_aux' metasenv subst context term = - 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) - in - try - CicTypeChecker.type_of_aux' metasenv context term - with CicTypeChecker.TypeCheckerFailure msg -> - raise (MetaSubstFailure ("Type checker failure: " ^ msg)) +(** {2 Format-like pretty printers} *) + +let fpp_gen ppf s = + Format.pp_print_string ppf s; + Format.pp_print_newline ppf (); + Format.pp_print_flush ppf () + +let fppsubst ppf subst = fpp_gen ppf (ppsubst subst) +let fppterm ppf term = fpp_gen ppf (CicPp.ppterm term) +let fppmetasenv ppf metasenv = fpp_gen ppf (ppmetasenv [] metasenv)