+(*
+ ||M|| This file is part of HELM, an Hypertextual, Electronic
+ ||A|| Library of Mathematics, developed at the Computer Science
+ ||T|| Department, University of Bologna, Italy.
+ ||I||
+ ||T|| HELM is free software; you can redistribute it and/or
+ ||A|| modify it under the terms of the GNU General Public License
+ \ / version 2 or (at your option) any later version.
+ \ / This software is distributed as is, NO WARRANTY.
+ V_______________________________________________________________ *)
+
+(* $Id$ *)
+
+(* TODO unify exceptions *)
+
+exception WrongUriToInductiveDefinition;;
+exception Impossible of int;;
+exception ReferenceToConstant;;
+exception ReferenceToVariable;;
+exception ReferenceToCurrentProof;;
+exception ReferenceToInductiveDefinition;;
+
+let debug = false
+let profile = false
+let debug_print s = if debug then prerr_endline (Lazy.force s)
+
+let fdebug = ref 1;;
+let debug t env s =
+ let rec debug_aux t i =
+ let module C = Cic in
+ let module U = UriManager in
+ CicPp.ppobj (C.Variable ("DEBUG", None, t, [], [])) ^ "\n" ^ i
+ in
+ if !fdebug = 0 then
+ debug_print (lazy (s ^ "\n" ^ List.fold_right debug_aux (t::env) ""))
+;;
+
+module type Strategy =
+ sig
+ type stack_term
+ type env_term
+ type config = int * env_term list * NCic.term * stack_term list
+ val to_env :
+ reduce: (config -> config) ->
+ unwind: (config -> NCic.term) ->
+ config -> env_term
+ val from_stack : stack_term -> config
+ val from_stack_list_for_unwind :
+ unwind: (config -> NCic.term) ->
+ stack_term list -> NCic.term list
+ val from_env : env_term -> config
+ val from_env_for_unwind :
+ unwind: (config -> NCic.term) ->
+ env_term -> NCic.term
+ val stack_to_env :
+ reduce: (config -> config) ->
+ unwind: (config -> NCic.term) ->
+ stack_term -> env_term
+ val compute_to_env :
+ reduce: (config -> config) ->
+ unwind: (config -> NCic.term) ->
+ int -> env_term list ->
+ NCic.term -> env_term
+ val compute_to_stack :
+ reduce: (config -> config) ->
+ unwind: (config -> NCic.term) ->
+ config -> stack_term
+ end
+;;
+
+module CallByValueByNameForUnwind' =
+ struct
+ type config = int * env_term list * NCic.term * stack_term list
+ and stack_term = config lazy_t * NCic.term lazy_t (* cbv, cbn *)
+ and env_term = config lazy_t * NCic.term lazy_t (* cbv, cbn *)
+ let to_env ~reduce ~unwind c = lazy (reduce c),lazy (unwind c)
+ let from_stack (c,_) = Lazy.force c
+ let from_stack_list_for_unwind ~unwind:_ l =
+ List.map (function (_,c) -> Lazy.force c) l
+ let from_env (c,_) = Lazy.force c
+ let from_env_for_unwind ~unwind:_ (_,c) = Lazy.force c
+ let stack_to_env ~reduce:_ ~unwind:_ config = config
+ let compute_to_env ~reduce ~unwind k e t =
+ lazy (reduce (k,e,t,[])), lazy (unwind (k,e,t,[]))
+ let compute_to_stack ~reduce ~unwind config =
+ lazy (reduce config), lazy (unwind config)
+ end
+;;
+
+
+(* {{{ module CallByValueByNameForUnwind =
+ struct
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ and stack_term = config
+ and env_term = config * config (* cbv, cbn *)
+ and ens_term = config * config (* cbv, cbn *)
+
+ let to_env c = c,c
+ let to_ens c = c,c
+ let from_stack config = config
+ let from_stack_list_for_unwind ~unwind l = List.map unwind l
+ let from_env (c,_) = c
+ let from_ens (c,_) = c
+ let from_env_for_unwind ~unwind (_,c) = unwind c
+ let from_ens_for_unwind ~unwind (_,c) = unwind c
+ let stack_to_env ~reduce ~unwind config = reduce config, (0,[],[],unwind config,[])
+ let compute_to_env ~reduce ~unwind k e ens t = (k,e,ens,t,[]), (k,e,ens,t,[])
+ let compute_to_stack ~reduce ~unwind config = config
+ end
+;;
+
+
+(* Old Machine *)
+module CallByNameStrategy =
+ struct
+ type stack_term = Cic.term
+ type env_term = Cic.term
+ type ens_term = Cic.term
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v = v
+ let to_ens v = v
+ let from_stack ~unwind v = v
+ let from_stack_list ~unwind l = l
+ let from_env v = v
+ let from_ens v = v
+ let from_env_for_unwind ~unwind v = v
+ let from_ens_for_unwind ~unwind v = v
+ let stack_to_env ~reduce ~unwind v = v
+ let compute_to_stack ~reduce ~unwind k e ens t = unwind k e ens t
+ let compute_to_env ~reduce ~unwind k e ens t = unwind k e ens t
+ end
+;;
+
+module CallByNameStrategy =
+ struct
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ and stack_term = config
+ and env_term = config
+ and ens_term = config
+
+ let to_env c = c
+ let to_ens c = c
+ let from_stack config = config
+ let from_stack_list_for_unwind ~unwind l = List.map unwind l
+ let from_env c = c
+ let from_ens c = c
+ let from_env_for_unwind ~unwind c = unwind c
+ let from_ens_for_unwind ~unwind c = unwind c
+ let stack_to_env ~reduce ~unwind config = 0,[],[],unwind config,[]
+ let compute_to_env ~reduce ~unwind k e ens t = k,e,ens,t,[]
+ let compute_to_stack ~reduce ~unwind config = config
+ end
+;;
+
+module CallByValueStrategy =
+ struct
+ type stack_term = Cic.term
+ type env_term = Cic.term
+ type ens_term = Cic.term
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v = v
+ let to_ens v = v
+ let from_stack ~unwind v = v
+ let from_stack_list ~unwind l = l
+ let from_env v = v
+ let from_ens v = v
+ let from_env_for_unwind ~unwind v = v
+ let from_ens_for_unwind ~unwind v = v
+ let stack_to_env ~reduce ~unwind v = v
+ let compute_to_stack ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
+ let compute_to_env ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
+ end
+;;
+
+module CallByValueStrategyByNameOnConstants =
+ struct
+ type stack_term = Cic.term
+ type env_term = Cic.term
+ type ens_term = Cic.term
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v = v
+ let to_ens v = v
+ let from_stack ~unwind v = v
+ let from_stack_list ~unwind l = l
+ let from_env v = v
+ let from_ens v = v
+ let from_env_for_unwind ~unwind v = v
+ let from_ens_for_unwind ~unwind v = v
+ let stack_to_env ~reduce ~unwind v = v
+ let compute_to_stack ~reduce ~unwind k e ens =
+ function
+ Cic.Const _ as t -> unwind k e ens t
+ | t -> reduce (k,e,ens,t,[])
+ let compute_to_env ~reduce ~unwind k e ens =
+ function
+ Cic.Const _ as t -> unwind k e ens t
+ | t -> reduce (k,e,ens,t,[])
+ end
+;;
+
+module LazyCallByValueStrategy =
+ struct
+ type stack_term = Cic.term lazy_t
+ type env_term = Cic.term lazy_t
+ type ens_term = Cic.term lazy_t
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v = lazy v
+ let to_ens v = lazy v
+ let from_stack ~unwind v = Lazy.force v
+ let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+ let from_env v = Lazy.force v
+ let from_ens v = Lazy.force v
+ let from_env_for_unwind ~unwind v = Lazy.force v
+ let from_ens_for_unwind ~unwind v = Lazy.force v
+ let stack_to_env ~reduce ~unwind v = v
+ let compute_to_stack ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
+ let compute_to_env ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
+ end
+;;
+
+module LazyCallByValueStrategyByNameOnConstants =
+ struct
+ type stack_term = Cic.term lazy_t
+ type env_term = Cic.term lazy_t
+ type ens_term = Cic.term lazy_t
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v = lazy v
+ let to_ens v = lazy v
+ let from_stack ~unwind v = Lazy.force v
+ let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+ let from_env v = Lazy.force v
+ let from_ens v = Lazy.force v
+ let from_env_for_unwind ~unwind v = Lazy.force v
+ let from_ens_for_unwind ~unwind v = Lazy.force v
+ let stack_to_env ~reduce ~unwind v = v
+ let compute_to_stack ~reduce ~unwind k e ens t =
+ lazy (
+ match t with
+ Cic.Const _ as t -> unwind k e ens t
+ | t -> reduce (k,e,ens,t,[]))
+ let compute_to_env ~reduce ~unwind k e ens t =
+ lazy (
+ match t with
+ Cic.Const _ as t -> unwind k e ens t
+ | t -> reduce (k,e,ens,t,[]))
+ end
+;;
+
+module LazyCallByNameStrategy =
+ struct
+ type stack_term = Cic.term lazy_t
+ type env_term = Cic.term lazy_t
+ type ens_term = Cic.term lazy_t
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v = lazy v
+ let to_ens v = lazy v
+ let from_stack ~unwind v = Lazy.force v
+ let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+ let from_env v = Lazy.force v
+ let from_ens v = Lazy.force v
+ let from_env_for_unwind ~unwind v = Lazy.force v
+ let from_ens_for_unwind ~unwind v = Lazy.force v
+ let stack_to_env ~reduce ~unwind v = v
+ let compute_to_stack ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
+ let compute_to_env ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
+ end
+;;
+
+module
+ LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns
+=
+ struct
+ type stack_term = reduce:bool -> Cic.term
+ type env_term = reduce:bool -> Cic.term
+ type ens_term = reduce:bool -> Cic.term
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v =
+ let value = lazy v in
+ fun ~reduce -> Lazy.force value
+ let to_ens v =
+ let value = lazy v in
+ fun ~reduce -> Lazy.force value
+ let from_stack ~unwind v = (v ~reduce:false)
+ let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+ let from_env v = (v ~reduce:true)
+ let from_ens v = (v ~reduce:true)
+ let from_env_for_unwind ~unwind v = (v ~reduce:true)
+ let from_ens_for_unwind ~unwind v = (v ~reduce:true)
+ let stack_to_env ~reduce ~unwind v = v
+ let compute_to_stack ~reduce ~unwind k e ens t =
+ let svalue =
+ lazy (
+ match t with
+ Cic.Const _ as t -> unwind k e ens t
+ | t -> reduce (k,e,ens,t,[])
+ ) in
+ let lvalue =
+ lazy (unwind k e ens t)
+ in
+ fun ~reduce ->
+ if reduce then Lazy.force svalue else Lazy.force lvalue
+ let compute_to_env ~reduce ~unwind k e ens t =
+ let svalue =
+ lazy (
+ match t with
+ Cic.Const _ as t -> unwind k e ens t
+ | t -> reduce (k,e,ens,t,[])
+ ) in
+ let lvalue =
+ lazy (unwind k e ens t)
+ in
+ fun ~reduce ->
+ if reduce then Lazy.force svalue else Lazy.force lvalue
+ end
+;;
+
+module ClosuresOnStackByValueFromEnvOrEnsStrategy =
+ struct
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ and stack_term = config
+ and env_term = config
+ and ens_term = config
+
+ let to_env config = config
+ let to_ens config = config
+ let from_stack config = config
+ let from_stack_list_for_unwind ~unwind l = List.map unwind l
+ let from_env v = v
+ let from_ens v = v
+ let from_env_for_unwind ~unwind config = unwind config
+ let from_ens_for_unwind ~unwind config = unwind config
+ let stack_to_env ~reduce ~unwind config = reduce config
+ let compute_to_env ~reduce ~unwind k e ens t = (k,e,ens,t,[])
+ let compute_to_stack ~reduce ~unwind config = config
+ end
+;;
+
+module ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy =
+ struct
+ type stack_term =
+ int * Cic.term list * Cic.term Cic.explicit_named_substitution * Cic.term
+ type env_term = Cic.term
+ type ens_term = Cic.term
+ type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
+ let to_env v = v
+ let to_ens v = v
+ let from_stack ~unwind (k,e,ens,t) = unwind k e ens t
+ let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+ let from_env v = v
+ let from_ens v = v
+ let from_env_for_unwind ~unwind v = v
+ let from_ens_for_unwind ~unwind v = v
+ let stack_to_env ~reduce ~unwind (k,e,ens,t) =
+ match t with
+ Cic.Const _ as t -> unwind k e ens t
+ | t -> reduce (k,e,ens,t,[])
+ let compute_to_env ~reduce ~unwind k e ens t =
+ unwind k e ens t
+ let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
+ end
+;;
+
+}}} *)
+
+module Reduction(RS : Strategy) =
+ struct
+ type env = RS.env_term list
+ type stack = RS.stack_term list
+ type config = int * env * NCic.term * stack
+
+ let rec unwind (k,e,t,s) =
+ let t =
+ if k = 0 then t
+ else
+ NCicSubstitution.psubst ~avoid_beta_redexes:true
+ true 0 (RS.from_env_for_unwind ~unwind) e t
+ in
+ if s = [] then t
+ else NCic.Appl(t::(RS.from_stack_list_for_unwind ~unwind s))
+ ;;
+
+ let list_nth l n = try List.nth l n with Failure _ -> assert false;;
+ let rec replace i s t =
+ match i,s with
+ | 0,_::tl -> t::tl
+ | n,he::tl -> he::(replace (n - 1) tl t)
+ | _,_ -> assert false
+ ;;
+
+ let rec reduce ~delta ?(subst = []) context : config -> config =
+ let rec aux = function
+ | k, e, NCic.Rel n, s when n <= k ->
+ let k',e',t',s' = RS.from_env (list_nth e (n-1)) in
+ aux (k',e',t',s'@s)
+ | k, _, NCic.Rel n, s as config (* when n > k *) ->
+ (match List.nth context (n - 1 - k) with
+ | (_,NCic.Decl _) -> config
+ | (_,NCic.Def (x,_)) -> aux (0,[],NCicSubstitution.lift (n - k) x,s))
+ | (k, e, NCic.Meta (n,l), s) as config ->
+ (try
+ let _,_, term,_ = NCicUtils.lookup_subst n subst in
+ aux (k, e, NCicSubstitution.subst_meta l term,s)
+ with NCicUtils.Subst_not_found _ -> config)
+ | (_, _, NCic.Sort _, _) as config -> config
+ | (_, _, NCic.Implicit _, _) -> assert false
+ | (_, _, NCic.Prod _, _) as config -> config
+ | (_, _, NCic.Lambda _, []) as config -> config
+ | (k, e, NCic.Lambda (_,_,t), p::s) ->
+ aux (k+1, (RS.stack_to_env ~reduce:aux ~unwind p)::e, t,s)
+ | (k, e, NCic.LetIn (_,_,m,t), s) ->
+ let m' = RS.compute_to_env ~reduce:aux ~unwind k e m in
+ aux (k+1, m'::e, t, s)
+ | (_, _, NCic.Appl [], _) -> assert false
+ | (k, e, NCic.Appl (he::tl), s) ->
+ let tl' =
+ List.map (fun t->RS.compute_to_stack ~reduce:aux ~unwind (k,e,t,[])) tl
+ in
+ aux (k, e, he, tl' @ s)
+ | (_, _, NCic.Const
+ (NReference.Ref (_,_,NReference.Def) as refer), s) as config ->
+ let _,_,body,_,_,height = NCicEnvironment.get_checked_def refer in
+ if delta > height then config else aux (0, [], body, s)
+ | (_, _, NCic.Const (NReference.Ref
+ (_,_,NReference.Fix (fixno,recindex)) as refer),s) as config ->
+ let fixes,_, height = NCicEnvironment.get_checked_fixes refer in
+ if delta > height then config else
+ (match
+ try Some (RS.from_stack (List.nth s recindex))
+ with Failure _ -> None
+ with
+ | None -> config
+ | Some recparam ->
+ match reduce ~delta:0 ~subst context recparam with
+ | (_,_,NCic.Const (NReference.Ref (_,_,NReference.Con _)), _) as c ->
+ let new_s =
+ replace recindex s (RS.compute_to_stack ~reduce:aux ~unwind c)
+ in
+ let _,_,_,_,body = List.nth fixes fixno in
+ aux (0, [], body, new_s)
+ | _ -> config)
+ | (_, _, NCic.Const _, _) as config -> config
+ | (k, e, NCic.Match (_,_,term,pl),s) as config ->
+ let decofix = function
+ | (_,_,NCic.Const(NReference.Ref(_,_,NReference.CoFix c)as refer),s)->
+ let cofixes,_,_ = NCicEnvironment.get_checked_cofixes refer in
+ let _,_,_,_,body = List.nth cofixes c in
+ reduce ~delta:0 ~subst context (0,[],body,s)
+ | config -> config
+ in
+ (match decofix (reduce ~delta:0 ~subst context (k,e,term,[])) with
+ | (_, _, NCic.Const (NReference.Ref (_,_,NReference.Con (_,j))),[]) ->
+ aux (k, e, List.nth pl (j-1), s)
+ | (_, _, NCic.Const
+ (NReference.Ref (_,_,NReference.Con (_,j)) as refer), s') ->
+ let leftno = NCicEnvironment.get_indty_leftno refer in
+ let _,params = HExtlib.split_nth leftno s' in
+ aux (k, e, List.nth pl (j-1), params@s)
+ | _ -> config)
+ in
+ aux
+ ;;
+
+ let whd ?(delta=0) ?(subst=[]) context t =
+ unwind (reduce ~delta ~subst context (0, [], t, []))
+ ;;
+
+ end
+;;
+
+
+(* {{{ ROTTO = rompe l'unificazione poiche' riduce gli argomenti di un'applicazione
+ senza ridurre la testa
+module R = Reduction CallByNameStrategy;; OK 56.368s
+module R = Reduction CallByValueStrategy;; ROTTO
+module R = Reduction CallByValueStrategyByNameOnConstants;; ROTTO
+module R = Reduction LazyCallByValueStrategy;; ROTTO
+module R = Reduction LazyCallByValueStrategyByNameOnConstants;; ROTTO
+module R = Reduction LazyCallByNameStrategy;; OK 0m56.398s
+module R = Reduction
+ LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns;;
+ OK 59.058s
+module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;; OK 58.583s
+module R = Reduction
+ ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy;; OK 58.094s
+module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);; OK 58.127s
+module R = Reduction(CallByValueByNameForUnwind);;
+module R = Reduction(CallByNameStrategy);;
+module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);;}}} *)
+module RS = CallByValueByNameForUnwind';;
+
+module R = Reduction(RS);;
+module U = UriManager;;
+
+let whd = R.whd
+
+(*
+let whd =
+ let profiler_whd = HExtlib.profile ~enable:profile "are_convertible.whd" in
+ fun ?(delta=true) ?(subst=[]) context t ->
+ profiler_whd.HExtlib.profile (whd ~delta ~subst context) t
+*)
+
+(* mimic ocaml (<< 3.08) "=" behaviour. Tests physical equality first then
+ * fallbacks to structural equality *)
+let (===) x y = Pervasives.compare x y = 0 ;;
+
+module C = NCic
+
+(* t1, t2 must be well-typed *)
+let are_convertible whd ?(subst=[]) ?(metasenv=[]) =
+ let rec aux test_equality_only context t1 t2 =
+ let rec aux2 test_equality_only t1 t2 =
+ if t1 === t2 then
+ true
+ else
+ match (t1,t2) with
+ | (C.Sort (C.Type a), C.Sort (C.Type b)) -> a <= b
+ | (C.Sort s1,C.Sort (C.Type _)) -> (not test_equality_only)
+ | (C.Sort s1, C.Sort s2) -> s1 = s2
+
+ | (C.Prod (name1,s1,t1), C.Prod(_,s2,t2)) ->
+ aux true context s1 s2 &&
+ aux test_equality_only ((name1, C.Decl s1)::context) t1 t2
+ | (C.Lambda (name1,s1,t1), C.Lambda(_,s2,t2)) ->
+ aux true context s1 s2 &&
+ aux true ((name1, C.Decl s1)::context) t1 t2
+ | (C.LetIn (name1,ty1,s1,t1), C.LetIn(_,ty2,s2,t2)) ->
+ aux test_equality_only context ty1 ty2 &&
+ aux test_equality_only context s1 s2 &&
+ aux test_equality_only ((name1, C.Def (s1,ty1))::context) t1 t2
+
+ | (C.Meta (n1,(s1, C.Irl i1)), C.Meta (n2,(s2, C.Irl i2)))
+ when n1 = n2 && s1 = s2 -> true
+ | (C.Meta (n1,(s1, l1)), C.Meta (n2,(s2, l2))) when n1 = n2 ->
+ let l1 = NCicUtils.expand_local_context l1 in
+ let l2 = NCicUtils.expand_local_context l2 in
+ (try List.for_all2
+ (fun t1 t2 -> aux test_equality_only context
+ (NCicSubstitution.lift s1 t1)
+ (NCicSubstitution.lift s2 t2))
+ l1 l2
+ with Invalid_argument _ -> false)
+
+ | C.Meta (n1,l1), _ ->
+ (try
+ let _,_,term,_ = NCicUtils.lookup_subst n1 subst in
+ let term = NCicSubstitution.subst_meta l1 term in
+ aux test_equality_only context term t2
+ with NCicUtils.Subst_not_found _ -> false)
+ | _, C.Meta (n2,l2) ->
+ (try
+ let _,_,term,_ = NCicUtils.lookup_subst n2 subst in
+ let term = NCicSubstitution.subst_meta l2 term in
+ aux test_equality_only context t1 term
+ with NCicUtils.Subst_not_found _ -> false)
+
+ | (C.Appl l1, C.Appl l2) ->
+ (try List.for_all2 (aux test_equality_only context) l1 l2
+ with Invalid_argument _ -> false)
+
+ | (C.Match (ref1,outtype1,term1,pl1),
+ C.Match (ref2,outtype2,term2,pl2)) ->
+ NReference.eq ref1 ref2 &&
+ aux test_equality_only context outtype1 outtype2 &&
+ aux test_equality_only context term1 term2 &&
+ (try List.for_all2 (aux test_equality_only context) pl1 pl2
+ with Invalid_argument _ -> false)
+
+ | (C.Implicit _, _) | (_, C.Implicit _) -> assert false
+ | (_,_) -> false
+ in
+ if aux2 test_equality_only t1 t2 then
+ true
+ else
+ let rec convert_machines = function
+ | [] -> true
+ | ((k1,env1,h1,s1),(k2,env2,h2,s2))::tl ->
+ aux2 test_equality_only
+ (R.unwind (k1,env1,h1,[])) (R.unwind (k2,env2,h2,[])) &&
+ let problems =
+ let red_stack =
+ List.map
+ (fun si-> R.reduce ~delta:0 ~subst context(RS.from_stack si))
+ in
+ try Some (List.combine (red_stack s1) (red_stack s2) @ tl)
+ with Invalid_argument _ -> None
+ in
+ match problems with
+ | None -> false
+ | Some problems -> convert_machines problems
+ in
+ convert_machines
+ [R.reduce ~delta:0 ~subst context (0,[],t1,[]),
+ R.reduce ~delta:0 ~subst context (0,[],t2,[])]
+ in
+ aux false
+;;
+
+let are_convertible = are_convertible whd
+
+let rec head_beta_reduce ?(delta=max_int) ?(upto=(-1)) t l =
+ match upto, t, l with
+ | 0, C.Appl l1, _ -> C.Appl (l1 @ l)
+ | 0, t, [] -> t
+ | 0, t, _ -> C.Appl (t::l)
+ | _, C.Appl (hd::tl), _ -> head_beta_reduce ~delta ~upto hd (tl @ l)
+ | _, C.Lambda(_,_,bo), arg::tl ->
+ let bo = NCicSubstitution.subst arg bo in
+ head_beta_reduce ~delta ~upto:(upto - 1) bo tl
+ | _, C.Const (NReference.Ref (height, _, NReference.Def) as re), _
+ when delta <= height ->
+ let _, _, bo, _, _, _ = NCicEnvironment.get_checked_def re in
+ head_beta_reduce ~upto ~delta bo l
+ | _, t, [] -> t
+ | _, t, _ -> C.Appl (t::l)
+;;
+
+let head_beta_reduce ?delta ?upto t = head_beta_reduce ?delta ?upto t [];;
+
+(* vim:set foldmethod=marker: *)