;;
(** finds the _pointers_ to subterms that are alpha-equivalent to wanted in t *)
-let find_subterms ~wanted ~context t =
- let rec find context w t =
- if ProofEngineReduction.alpha_equivalence w t then
- [context,t]
- else
+let find_subterms ~subst ~metasenv ~ugraph ~wanted ~context t =
+ let rec find subst metasenv ugraph context w t =
+ try
+ let subst,metasenv,ugraph =
+ CicUnification.fo_unif_subst subst context metasenv w t ugraph
+ in
+ subst,metasenv,ugraph,[context,t]
+ with
+ CicUnification.UnificationFailure _
+ | CicUnification.Uncertain _ ->
match t with
| Cic.Sort _
- | Cic.Rel _ -> []
+ | Cic.Rel _ -> subst,metasenv,ugraph,[]
| Cic.Meta (_, ctx) ->
List.fold_left (
- fun acc e ->
+ fun (subst,metasenv,ugraph,acc) e ->
match e with
- | None -> acc
- | Some t -> find context w t @ acc
- ) [] ctx
+ | None -> subst,metasenv,ugraph,acc
+ | Some t ->
+ let subst,metasenv,ugraph,res =
+ find subst metasenv ugraph context w t
+ in
+ subst,metasenv,ugraph, res @ acc
+ ) (subst,metasenv,ugraph,[]) ctx
| Cic.Lambda (name, t1, t2)
| Cic.Prod (name, t1, t2) ->
- find context w t1 @
- find (Some (name, Cic.Decl t1)::context)
+ let subst,metasenv,ugraph,rest1 =
+ find subst metasenv ugraph context w t1 in
+ let subst,metasenv,ugraph,rest2 =
+ find subst metasenv ugraph (Some (name, Cic.Decl t1)::context)
(CicSubstitution.lift 1 w) t2
+ in
+ subst,metasenv,ugraph,rest1 @ rest2
| Cic.LetIn (name, t1, t2) ->
- find context w t1 @
- find (Some (name, Cic.Def (t1,None))::context)
+ let subst,metasenv,ugraph,rest1 =
+ find subst metasenv ugraph context w t1 in
+ let subst,metasenv,ugraph,rest2 =
+ find subst metasenv ugraph (Some (name, Cic.Def (t1,None))::context)
(CicSubstitution.lift 1 w) t2
+ in
+ subst,metasenv,ugraph,rest1 @ rest2
| Cic.Appl l ->
- List.fold_left (fun acc t -> find context w t @ acc) [] l
- | Cic.Cast (t, ty) -> find context w t @ find context w ty
+ List.fold_left
+ (fun (subst,metasenv,ugraph,acc) t ->
+ let subst,metasenv,ugraph,res =
+ find subst metasenv ugraph context w t
+ in
+ subst,metasenv,ugraph,res @ acc)
+ (subst,metasenv,ugraph,[]) l
+ | Cic.Cast (t, ty) ->
+ let subst,metasenv,ugraph,rest =
+ find subst metasenv ugraph context w t in
+ let subst,metasenv,ugraph,resty =
+ find subst metasenv ugraph context w ty
+ in
+ subst,metasenv,ugraph,rest @ resty
| Cic.Implicit _ -> assert false
| Cic.Const (_, esubst)
| Cic.Var (_, esubst)
| Cic.MutInd (_, _, esubst)
| Cic.MutConstruct (_, _, _, esubst) ->
- List.fold_left (fun acc (_, t) -> find context w t @ acc) [] esubst
+ List.fold_left
+ (fun (subst,metasenv,ugraph,acc) (_, t) ->
+ let subst,metasenv,ugraph,res =
+ find subst metasenv ugraph context w t
+ in
+ subst,metasenv,ugraph,res @ acc)
+ (subst,metasenv,ugraph,[]) esubst
| Cic.MutCase (_, _, outty, indterm, patterns) ->
- find context w outty @ find context w indterm @
- List.fold_left (fun acc p -> find context w p @ acc) [] patterns
+ let subst,metasenv,ugraph,resoutty =
+ find subst metasenv ugraph context w outty in
+ let subst,metasenv,ugraph,resindterm =
+ find subst metasenv ugraph context w indterm in
+ let subst,metasenv,ugraph,respatterns =
+ List.fold_left
+ (fun (subst,metasenv,ugraph,acc) p ->
+ let subst,metaseng,ugraph,res =
+ find subst metasenv ugraph context w p
+ in
+ subst,metasenv,ugraph,res @ acc
+ ) (subst,metasenv,ugraph,[]) patterns
+ in
+ subst,metasenv,ugraph,resoutty @ resindterm @ respatterns
| Cic.Fix (_, funl) ->
let tys =
List.map (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funl
in
List.fold_left (
- fun acc (_, _, ty, bo) ->
- find context w ty @ find (tys @ context) w bo @ acc
- ) [] funl
+ fun (subst,metasenv,ugraph,acc) (_, _, ty, bo) ->
+ let subst,metasenv,ugraph,resty =
+ find subst metasenv ugraph context w ty in
+ let subst,metasenv,ugraph,resbo =
+ find subst metasenv ugraph (tys @ context) w bo
+ in
+ subst,metasenv,ugraph, resty @ resbo @ acc
+ ) (subst,metasenv,ugraph,[]) funl
| Cic.CoFix (_, funl) ->
let tys =
List.map (fun (n,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funl
in
List.fold_left (
- fun acc (_, ty, bo) ->
- find context w ty @ find (tys @ context) w bo @ acc
- ) [] funl
+ fun (subst,metasenv,ugraph,acc) (_, ty, bo) ->
+ let subst,metasenv,ugraph,resty =
+ find subst metasenv ugraph context w ty in
+ let subst,metasenv,ugraph,resbo =
+ find subst metasenv ugraph (tys @ context) w bo
+ in
+ subst,metasenv,ugraph, resty @ resbo @ acc
+ ) (subst,metasenv,ugraph,[]) funl
in
- find context wanted t
+ find subst metasenv ugraph context wanted t
-let select ~context ~term ~pattern:(wanted,where) =
+let select_in_term ~metasenv ~context ~ugraph ~term ~pattern:(wanted,where) =
let add_ctx context name entry =
(Some (name, entry)) :: context
in
+ let map2 error_msg f l1 l2 =
+ try
+ List.map2 f l1 l2
+ with
+ | Invalid_argument _ -> raise (Bad_pattern error_msg)
+ in
let rec aux context where term =
match (where, term) with
| Cic.Implicit (Some `Hole), t -> [context,t]
| Cic.Implicit None,_ -> []
| Cic.Meta (_, ctxt1), Cic.Meta (_, ctxt2) ->
List.concat
- (List.map2
+ (map2 "wrong number of argument in explicit substitution"
(fun t1 t2 ->
(match (t1, t2) with
Some t1, Some t2 -> aux context t1 t2
List.map (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs2
in
List.concat
- (List.map2
+ (map2 "wrong number of mutually recursive functions"
(fun (_, _, ty1, bo1) (_, _, ty2, bo2) ->
aux context ty1 ty2 @ aux (tys @ context) bo1 bo2)
funs1 funs2)
List.map (fun (n,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs2
in
List.concat
- (List.map2
+ (map2 "wrong number of mutually co-recursive functions"
(fun (_, ty1, bo1) (_, ty2, bo2) ->
aux context ty1 ty2 @ aux (tys @ context) bo1 bo2)
funs1 funs2)
(CicPp.ppterm x)
(CicPp.ppterm y)))
and auxs context terms1 terms2 = (* as aux for list of terms *)
- List.concat (List.map2 (fun t1 t2 -> aux context t1 t2) terms1 terms2)
+ List.concat (map2 "wrong number of arguments in application"
+ (fun t1 t2 -> aux context t1 t2) terms1 terms2)
in
+ let context_len = List.length context in
let roots = aux context where term in
match wanted with
- None -> roots
+ None -> [],metasenv,ugraph,roots
| Some wanted ->
let rec find_in_roots =
function
- [] -> []
- | (context,where)::tl ->
- let tl' = find_in_roots tl in
- let found =
- let wanted = CicSubstitution.lift (List.length context) wanted in
- find_subterms ~wanted ~context where
+ [] -> [],metasenv,ugraph,[]
+ | (context',where)::tl ->
+ let subst,metasenv,ugraph,tl' = find_in_roots tl in
+ let subst,metasenv,ugraph,found =
+ let wanted, metasenv, ugraph = wanted context' metasenv ugraph in
+ find_subterms ~subst ~metasenv ~ugraph ~wanted ~context:context'
+ where
in
- found @ tl'
+ subst,metasenv,ugraph,found @ tl'
in
find_in_roots roots
+(** create a pattern from a term and a list of subterms.
+* the pattern is granted to have a ? for every subterm that has no selected
+* subterms
+* @param equality equality function used while walking the term. Defaults to
+* physical equality (==) *)
let pattern_of ?(equality=(==)) ~term terms =
let (===) x y = equality x y in
+ let not_found = false, Cic.Implicit None in
let rec aux t =
match t with
- | t when List.exists (fun t' -> t === t') terms -> Cic.Implicit (Some `Hole)
- | Cic.Var (uri, subst) -> Cic.Var (uri, aux_subst subst)
+ | t when List.exists (fun t' -> t === t') terms ->
+ true,Cic.Implicit (Some `Hole)
+ | Cic.Var (uri, subst) ->
+ let b,subst = aux_subst subst in
+ if b then
+ true,Cic.Var (uri, subst)
+ else
+ not_found
| Cic.Meta (i, ctxt) ->
- let ctxt =
- List.map (function None -> None | Some t -> Some (aux t)) ctxt
+ let b,ctxt =
+ List.fold_right
+ (fun e (b,ctxt) ->
+ match e with
+ None -> b,None::ctxt
+ | Some t -> let bt,t = aux t in b||bt ,Some t::ctxt
+ ) ctxt (false,[])
in
- Cic.Meta (i, ctxt)
- | Cic.Cast (t, ty) -> Cic.Cast (aux t, aux ty)
- | Cic.Prod (name, s, t) -> Cic.Prod (name, aux s, aux t)
- | Cic.Lambda (name, s, t) -> Cic.Lambda (name, aux s, aux t)
- | Cic.LetIn (name, s, t) -> Cic.LetIn (name, aux s, aux t)
- | Cic.Appl terms -> Cic.Appl (List.map aux terms)
- | Cic.Const (uri, subst) -> Cic.Const (uri, aux_subst subst)
- | Cic.MutInd (uri, tyno, subst) -> Cic.MutInd (uri, tyno, aux_subst subst)
+ if b then
+ true,Cic.Meta (i, ctxt)
+ else
+ not_found
+ | Cic.Cast (te, ty) ->
+ let b1,te = aux te in
+ let b2,ty = aux ty in
+ if b1||b2 then true,Cic.Cast (te, ty)
+ else
+ not_found
+ | Cic.Prod (name, s, t) ->
+ let b1,s = aux s in
+ let b2,t = aux t in
+ if b1||b2 then
+ true, Cic.Prod (name, s, t)
+ else
+ not_found
+ | Cic.Lambda (name, s, t) ->
+ let b1,s = aux s in
+ let b2,t = aux t in
+ if b1||b2 then
+ true, Cic.Lambda (name, s, t)
+ else
+ not_found
+ | Cic.LetIn (name, s, t) ->
+ let b1,s = aux s in
+ let b2,t = aux t in
+ if b1||b2 then
+ true, Cic.LetIn (name, s, t)
+ else
+ not_found
+ | Cic.Appl terms ->
+ let b,terms =
+ List.fold_right
+ (fun t (b,terms) ->
+ let bt,t = aux t in
+ b||bt,t::terms
+ ) terms (false,[])
+ in
+ if b then
+ true,Cic.Appl terms
+ else
+ not_found
+ | Cic.Const (uri, subst) ->
+ let b,subst = aux_subst subst in
+ if b then
+ true, Cic.Const (uri, subst)
+ else
+ not_found
+ | Cic.MutInd (uri, tyno, subst) ->
+ let b,subst = aux_subst subst in
+ if b then
+ true, Cic.MutInd (uri, tyno, subst)
+ else
+ not_found
| Cic.MutConstruct (uri, tyno, consno, subst) ->
- Cic.MutConstruct (uri, tyno, consno, aux_subst subst)
+ let b,subst = aux_subst subst in
+ if b then
+ true, Cic.MutConstruct (uri, tyno, consno, subst)
+ else
+ not_found
| Cic.MutCase (uri, tyno, outty, t, pat) ->
- Cic.MutCase (uri, tyno, aux outty, aux t, List.map aux pat)
+ let b1,outty = aux outty in
+ let b2,t = aux t in
+ let b3,pat =
+ List.fold_right
+ (fun t (b,pat) ->
+ let bt,t = aux t in
+ bt||b,t::pat
+ ) pat (false,[])
+ in
+ if b1 || b2 || b3 then
+ true, Cic.MutCase (uri, tyno, outty, t, pat)
+ else
+ not_found
| Cic.Fix (funno, funs) ->
- let funs =
- List.map (fun (name, i, ty, bo) -> (name, i, aux ty, aux bo)) funs
+ let b,funs =
+ List.fold_right
+ (fun (name, i, ty, bo) (b,funs) ->
+ let b1,ty = aux ty in
+ let b2,bo = aux bo in
+ b||b1||b2, (name, i, ty, bo)::funs) funs (false,[])
in
- Cic.Fix (funno, funs)
+ if b then
+ true, Cic.Fix (funno, funs)
+ else
+ not_found
| Cic.CoFix (funno, funs) ->
- let funs =
- List.map (fun (name, ty, bo) -> (name, aux ty, aux bo)) funs
+ let b,funs =
+ List.fold_right
+ (fun (name, ty, bo) (b,funs) ->
+ let b1,ty = aux ty in
+ let b2,bo = aux bo in
+ b||b1||b2, (name, ty, bo)::funs) funs (false,[])
in
- Cic.CoFix (funno, funs)
+ if b then
+ true, Cic.CoFix (funno, funs)
+ else
+ not_found
| Cic.Rel _
| Cic.Sort _
- | Cic.Implicit _ -> t
+ | Cic.Implicit _ -> not_found
and aux_subst subst =
- List.map (fun (uri, t) -> (uri, aux t)) subst
+ List.fold_right
+ (fun (uri, t) (b,subst) ->
+ let b1,t = aux t in
+ b||b1,(uri, t)::subst) subst (false,[])
+ in
+ snd (aux term)
+
+exception Fail of string
+
+ (** select metasenv conjecture pattern
+ * select all subterms of [conjecture] matching [pattern].
+ * It returns the set of matched terms (that can be compared using physical
+ * equality to the subterms of [conjecture]) together with their contexts.
+ * The representation of the set mimics the ProofEngineTypes.pattern type:
+ * a list of hypothesis (names of) together with the list of its matched
+ * subterms (and their contexts) + the list of matched subterms of the
+ * with their context conclusion. Note: in the result the list of hypothesis
+ * has an entry for each entry in the context and in the same order.
+ * Of course the list of terms (with their context) associated to the
+ * hypothesis name may be empty.
+ *
+ * @raise Bad_pattern
+ * *)
+ let select ~metasenv ~ugraph ~conjecture:(_,context,ty)
+ ~pattern:(what,hyp_patterns,goal_pattern)
+ =
+ let find_pattern_for name =
+ try Some (snd (List.find (fun (n, pat) -> Cic.Name n = name) hyp_patterns))
+ with Not_found -> None in
+ let subst,metasenv,ugraph,ty_terms =
+ select_in_term ~metasenv ~context ~ugraph ~term:ty
+ ~pattern:(what,goal_pattern) in
+ let context_len = List.length context in
+ let subst,metasenv,ugraph,context_terms =
+ let subst,metasenv,ugraph,res,_ =
+ (List.fold_right
+ (fun entry (subst,metasenv,ugraph,res,context) ->
+ match entry with
+ None -> subst,metasenv,ugraph,(None::res),(None::context)
+ | Some (name,Cic.Decl term) ->
+ (match find_pattern_for name with
+ | None ->
+ subst,metasenv,ugraph,((Some (`Decl []))::res),(entry::context)
+ | Some pat ->
+ let subst,metasenv,ugraph,terms =
+ select_in_term ~metasenv ~context ~ugraph ~term
+ ~pattern:(what,pat)
+ in
+ subst,metasenv,ugraph,((Some (`Decl terms))::res),
+ (entry::context))
+ | Some (name,Cic.Def (bo, ty)) ->
+ (match find_pattern_for name with
+ | None ->
+ let selected_ty=match ty with None -> None | Some _ -> Some [] in
+ subst,metasenv,ugraph,((Some (`Def ([],selected_ty)))::res),
+ (entry::context)
+ | Some pat ->
+ let subst,metasenv,ugraph,terms_bo =
+ select_in_term ~metasenv ~context ~ugraph ~term:bo
+ ~pattern:(what,pat) in
+ let subst,metasenv,ugraph,terms_ty =
+ match ty with
+ None -> subst,metasenv,ugraph,None
+ | Some ty ->
+ let subst,metasenv,ugraph,res =
+ select_in_term ~metasenv ~context ~ugraph ~term:ty
+ ~pattern:(what,pat)
+ in
+ subst,metasenv,ugraph,Some res
+ in
+ subst,metasenv,ugraph,((Some (`Def (terms_bo,terms_ty)))::res),
+ (entry::context))
+ ) context (subst,metasenv,ugraph,[],[]))
+ in
+ subst,metasenv,ugraph,res
+ in
+ subst,metasenv,ugraph,context_terms, ty_terms
+
+(** locate_in_term equality what where context
+* [what] must match a subterm of [where] according to [equality]
+* It returns the matched terms together with their contexts in [where]
+* [equality] defaults to physical equality
+* [context] must be the context of [where]
+*)
+let locate_in_term ?(equality=(fun _ -> (==))) what ~where context =
+ let add_ctx context name entry =
+ (Some (name, entry)) :: context in
+ let rec aux context where =
+ if equality context what where then [context,where]
+ else
+ match where with
+ | Cic.Implicit _
+ | Cic.Meta _
+ | Cic.Rel _
+ | Cic.Sort _
+ | Cic.Var _
+ | Cic.Const _
+ | Cic.MutInd _
+ | Cic.MutConstruct _ -> []
+ | Cic.Cast (te, ty) -> aux context te @ aux context ty
+ | Cic.Prod (name, s, t)
+ | Cic.Lambda (name, s, t) ->
+ aux context s @ aux (add_ctx context name (Cic.Decl s)) t
+ | Cic.LetIn (name, s, t) ->
+ aux context s @ aux (add_ctx context name (Cic.Def (s,None))) t
+ | Cic.Appl tl -> auxs context tl
+ | Cic.MutCase (_, _, out, t, pat) ->
+ aux context out @ aux context t @ auxs context pat
+ | Cic.Fix (_, funs) ->
+ let tys =
+ List.map (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs
+ in
+ List.concat
+ (List.map
+ (fun (_, _, ty, bo) ->
+ aux context ty @ aux (tys @ context) bo)
+ funs)
+ | Cic.CoFix (_, funs) ->
+ let tys =
+ List.map (fun (n,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs
+ in
+ List.concat
+ (List.map
+ (fun (_, ty, bo) ->
+ aux context ty @ aux (tys @ context) bo)
+ funs)
+ and auxs context tl = (* as aux for list of terms *)
+ List.concat (List.map (fun t -> aux context t) tl)
in
- aux term
+ aux context where
+
+(** locate_in_conjecture equality what where context
+* [what] must match a subterm of [where] according to [equality]
+* It returns the matched terms together with their contexts in [where]
+* [equality] defaults to physical equality
+* [context] must be the context of [where]
+*)
+let locate_in_conjecture ?(equality=fun _ -> (==)) what (_,context,ty) =
+ let context,res =
+ List.fold_right
+ (fun entry (context,res) ->
+ match entry with
+ None -> entry::context, res
+ | Some (_, Cic.Decl ty) ->
+ let res = res @ locate_in_term what ~where:ty context in
+ let context' = entry::context in
+ context',res
+ | Some (_, Cic.Def (bo,ty)) ->
+ let res = res @ locate_in_term what ~where:bo context in
+ let res =
+ match ty with
+ None -> res
+ | Some ty ->
+ res @ locate_in_term what ~where:ty context in
+ let context' = entry::context in
+ context',res
+ ) context ([],[])
+ in
+ res @ locate_in_term what ~where:ty context
+(* saturate_term newmeta metasenv context ty goal_arity *)
+(* Given a type [ty] (a backbone), it returns its suffix of length *)
+(* [goal_arity] head and a new metasenv in which there is new a META for each *)
+(* hypothesis, a list of arguments for the new applications and the index of *)
+(* the last new META introduced. The nth argument in the list of arguments is *)
+(* just the nth new META. *)
+let saturate_term newmeta metasenv context ty goal_arity =
+ let module C = Cic in
+ let module S = CicSubstitution in
+ assert (goal_arity >= 0);
+ let rec aux newmeta ty =
+ match ty with
+ C.Cast (he,_) -> aux newmeta he
+(* CSC: patch to generate ?1 : ?2 : Type in place of ?1 : Type to simulate ?1 :< Type
+ (* If the expected type is a Type, then also Set is OK ==>
+ * we accept any term of type Type *)
+ (*CSC: BUG HERE: in this way it is possible for the term of
+ * type Type to be different from a Sort!!! *)
+ | C.Prod (name,(C.Sort (C.Type _) as s),t) ->
+ (* TASSI: ask CSC if BUG HERE refers to the C.Cast or C.Propd case *)
+ let irl =
+ CicMkImplicit.identity_relocation_list_for_metavariable context
+ in
+ let newargument = C.Meta (newmeta+1,irl) in
+ let (res,newmetasenv,arguments,lastmeta) =
+ aux (newmeta + 2) (S.subst newargument t)
+ in
+ res,
+ (newmeta,[],s)::(newmeta+1,context,C.Meta (newmeta,[]))::newmetasenv,
+ newargument::arguments,lastmeta
+*)
+ | C.Prod (name,s,t) ->
+ let irl =
+ CicMkImplicit.identity_relocation_list_for_metavariable context
+ in
+ let newargument = C.Meta (newmeta,irl) in
+ let res,newmetasenv,arguments,lastmeta,prod_no =
+ aux (newmeta + 1) (S.subst newargument t)
+ in
+ if prod_no + 1 = goal_arity then
+ let head = CicReduction.normalize ~delta:false context ty in
+ head,[],[],lastmeta,goal_arity + 1
+ else
+ (** NORMALIZE RATIONALE
+ * we normalize the target only NOW since we may be in this case:
+ * A1 -> A2 -> T where T = (\lambda x.A3 -> P) k
+ * and we want a mesasenv with ?1:A1 and ?2:A2 and not
+ * ?1, ?2, ?3 (that is the one we whould get if we start from the
+ * beta-normalized A1 -> A2 -> A3 -> P **)
+ let s' = CicReduction.normalize ~delta:false context s in
+ res,(newmeta,context,s')::newmetasenv,newargument::arguments,
+ lastmeta,prod_no + 1
+ | t ->
+ let head = CicReduction.normalize ~delta:false context t in
+ match CicReduction.whd context head with
+ C.Prod _ as head' -> aux newmeta head'
+ | _ -> head,[],[],newmeta,0
+ in
+ (* WARNING: here we are using the invariant that above the most *)
+ (* recente new_meta() there are no used metas. *)
+ let res,newmetasenv,arguments,lastmeta,_ = aux newmeta ty in
+ res,metasenv @ newmetasenv,arguments,lastmeta
+
+let lookup_type metasenv context hyp =
+ let rec aux p = function
+ | Some (Cic.Name name, Cic.Decl t) :: _ when name = hyp -> p, t
+ | Some (Cic.Name name, Cic.Def (_, Some t)) :: _ when name = hyp -> p, t
+ | Some (Cic.Name name, Cic.Def (u, _)) :: tail when name = hyp ->
+ p, fst (CicTypeChecker.type_of_aux' metasenv tail u CicUniv.empty_ugraph)
+ | _ :: tail -> aux (succ p) tail
+ | [] -> raise (ProofEngineTypes.Fail "lookup_type: not premise in the current goal")
+ in
+ aux 1 context