aboutsummaryrefslogtreecommitdiff
path: root/kernel/generic.ml
diff options
context:
space:
mode:
authorfilliatr1999-08-17 14:05:47 +0000
committerfilliatr1999-08-17 14:05:47 +0000
commitc85ed98ae100c524bb572ebbfd2f4228a11932be (patch)
treeb461527c8fb68d464f3cea9832787e8352421c10 /kernel/generic.ml
parent6b2bb43c4eb815af8f7128b2f2848157c6b020d7 (diff)
generic, term et evd
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@9 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'kernel/generic.ml')
-rw-r--r--kernel/generic.ml604
1 files changed, 604 insertions, 0 deletions
diff --git a/kernel/generic.ml b/kernel/generic.ml
new file mode 100644
index 0000000000..9adc53ce68
--- /dev/null
+++ b/kernel/generic.ml
@@ -0,0 +1,604 @@
+
+(* $Id$ *)
+
+open Util
+open Pp
+open Names
+
+(********************************************************************)
+(* Generic syntax of terms with de Bruijn indexes *)
+(********************************************************************)
+
+type 'oper term =
+ | DOP0 of 'oper (* atomic terms *)
+ | DOP1 of 'oper * 'oper term (* operator of arity 1 *)
+ | DOP2 of 'oper * 'oper term * 'oper term (* operator of arity 2 *)
+ | DOPN of 'oper * 'oper term array (* operator of variadic arity *)
+ | DOPL of 'oper * 'oper term list (* operator of variadic arity *)
+ | DLAM of name * 'oper term (* deBruijn binder on one term*)
+ | DLAMV of name * 'oper term array (* deBruijn binder on many terms*)
+ | VAR of identifier (* named variable *)
+ | Rel of int (* variable as deBruijn index *)
+
+exception FreeVar
+exception Occur
+
+let isRel = function Rel _ -> true | _ -> false
+let isVAR = function VAR _ -> true | _ -> false
+
+(* returns the list of free debruijn indices in a term *)
+
+let free_rels m =
+ let rec frec depth acc = function
+ | Rel n -> if n >= depth then Intset.add (n-depth+1) acc else acc
+ | DOPN(_,cl) -> Array.fold_left (frec depth) acc cl
+ | DOPL(_,cl) -> List.fold_left (frec depth) acc cl
+ | DOP2(_,c1,c2) -> frec depth (frec depth acc c1) c2
+ | DOP1(_,c) -> frec depth acc c
+ | DLAM(_,c) -> frec (depth+1) acc c
+ | DLAMV(_,cl) -> Array.fold_left (frec (depth+1)) acc cl
+ | VAR _ -> acc
+ | DOP0 _ -> acc
+ in
+ frec 1 Intset.empty m
+
+(* (closedn n M) raises FreeVar if a variable of height greater than n
+ occurs in M, returns () otherwise *)
+
+let closedn =
+ let rec closed_rec n = function
+ | Rel(m) -> if m>n then raise FreeVar
+ | VAR _ -> ()
+ | DOPN(_,cl) -> Array.iter (closed_rec n) cl
+ | DOPL(_,cl) -> List.iter (closed_rec n) cl
+ | DOP2(_,c1,c2) -> closed_rec n c1; closed_rec n c2
+ | DOP1(_,c) -> closed_rec n c
+ | DLAM(_,c) -> closed_rec (n+1) c
+ | DLAMV(_,v) -> Array.iter (closed_rec (n+1)) v
+ | _ -> ()
+ in
+ closed_rec
+
+(* (closed M) is true iff M is a (deBruijn) closed term *)
+
+let closed0 term =
+ try closedn 0 term; true with FreeVar -> false
+
+(* (noccurn n M) returns true iff (Rel n) does NOT occur in term M *)
+
+let noccurn n term =
+ let rec occur_rec n = function
+ | Rel(m) -> if m = n then raise Occur
+ | VAR _ -> ()
+ | DOPN(_,cl) -> Array.iter (occur_rec n) cl
+ | DOPL(_,cl) -> List.iter (occur_rec n) cl
+ | DOP1(_,c) -> occur_rec n c
+ | DOP2(_,c1,c2) -> occur_rec n c1; occur_rec n c2
+ | DLAM(_,c) -> occur_rec (n+1) c
+ | DLAMV(_,v) -> Array.iter (occur_rec (n+1)) v
+ | _ -> ()
+ in
+ try occur_rec n term; true with Occur -> false
+
+(* (noccur_bet n m M) returns true iff (Rel p) does NOT occur in term M
+ for n <= p < n+m *)
+
+let noccur_bet n m term =
+ let rec occur_rec n = function
+ | Rel(p) -> if n<=p && p<n+m then raise Occur
+ | VAR _ -> ()
+ | DOPN(_,cl) -> Array.iter (occur_rec n) cl
+ | DOPL(_,cl) -> List.iter (occur_rec n) cl
+ | DOP1(_,c) -> occur_rec n c
+ | DOP2(_,c1,c2) -> occur_rec n c1; occur_rec n c2
+ | DLAM(_,c) -> occur_rec (n+1) c
+ | DLAMV(_,v) -> Array.iter (occur_rec (n+1)) v
+ | _ -> ()
+ in
+ try occur_rec n term; true with Occur -> false
+
+(* Explicit lifts and basic operations *)
+type lift_spec =
+ | ELID
+ | ELSHFT of lift_spec * int (* ELSHFT(l,n) == lift of n, then apply lift l *)
+ | ELLFT of int * lift_spec (* ELLFT(n,l) == apply l to de Bruijn > n *)
+ (* i.e under n binders *)
+
+(* compose a relocation of magnitude n *)
+let rec el_shft n = function
+ | ELSHFT(el,k) -> el_shft (k+n) el
+ | el -> if n = 0 then el else ELSHFT(el,n)
+
+
+(* cross n binders *)
+let rec el_liftn n = function
+ | ELID -> ELID
+ | ELLFT(k,el) -> el_liftn (n+k) el
+ | el -> if n=0 then el else ELLFT(n, el)
+
+let el_lift el = el_liftn 1 el
+
+(* relocation of de Bruijn n in an explicit lift *)
+let rec reloc_rel n = function
+ | ELID -> n
+ | ELLFT(k,el) ->
+ if n <= k then n else (reloc_rel (n-k) el) + k
+ | ELSHFT(el,k) -> (reloc_rel (n+k) el)
+
+
+(* The generic lifting function *)
+let rec exliftn el = function
+ | Rel i -> Rel(reloc_rel i el)
+ | DOPN(oper,cl) -> DOPN(oper, Array.map (exliftn el) cl)
+ | DOPL(oper,cl) -> DOPL(oper, List.map (exliftn el) cl)
+ | DOP1(oper,c) -> DOP1(oper, exliftn el c)
+ | DOP2(oper,c1,c2) -> DOP2(oper, exliftn el c1, exliftn el c2)
+ | DLAM(na,c) -> DLAM(na, exliftn (el_lift el) c)
+ | DLAMV(na,v) -> DLAMV(na, Array.map (exliftn (el_lift el)) v)
+ | x -> x
+
+
+(* Lifting the binding depth across k bindings *)
+
+let liftn k n =
+ match el_liftn (pred n) (el_shft k ELID) with
+ | ELID -> (fun c -> c)
+ | el -> exliftn el
+
+let lift k = liftn k 1
+let lift1 c = exliftn (ELSHFT(ELID,1)) c
+
+
+(* explicit substitutions of type 'a *)
+type 'a subs =
+ | ESID (* ESID = identity *)
+ | CONS of 'a * 'a subs (* CONS(t,S) = (S.t) parallel substitution *)
+ | SHIFT of int * 'a subs (* SHIFT(n,S) = (^n o S) terms in S are relocated *)
+ (* with n vars *)
+ | LIFT of int * 'a subs (* LIFT(n,S) = (%n S) stands for ((^n o S).n...1) *)
+
+(* operations of subs: collapses constructors when possible.
+ * Needn't be recursive if we always use these functions
+ *)
+let subs_cons(x,s) = CONS(x,s)
+
+let subs_lift = function
+ | ESID -> ESID (* the identity lifted is still the identity *)
+ (* (because (^1.1) --> id) *)
+ | LIFT (n,lenv) -> LIFT (n+1, lenv)
+ | lenv -> LIFT (1,lenv)
+
+let subs_shft = function
+ | (0, s) -> s
+ | (n, SHIFT (k,s1)) -> SHIFT (k+n, s1)
+ | (n, s) -> SHIFT (n,s)
+
+
+(* Expands de Bruijn k in the explicit substitution subs
+ * lams accumulates de shifts to perform when retrieving the i-th value
+ * the rules used are the following:
+ *
+ * [id]k --> k
+ * [S.t]1 --> t
+ * [S.t]k --> [S](k-1) if k > 1
+ * [^n o S] k --> [^n]([S]k)
+ * [(%n S)] k --> k if k <= n
+ * [(%n S)] k --> [^n]([S](k-n))
+ *
+ * the result is (Inr k) when the variable is just relocated
+ *)
+let rec exp_rel lams k subs =
+ match (k,subs) with
+ | (1, CONS (def,_)) -> Inl(lams,def)
+ | (_, CONS (_,l)) -> exp_rel lams (pred k) l
+ | (_, LIFT (n,_)) when k<=n -> Inr(lams+k)
+ | (_, LIFT (n,l)) -> exp_rel (n+lams) (k-n) l
+ | (_, SHIFT (n,s)) -> exp_rel (n+lams) k s
+ | (_, ESID) -> Inr(lams+k)
+
+let expand_rel k subs = exp_rel 0 k subs
+
+
+(* (subst1 M c) substitutes M for Rel(1) in c
+ we generalise it to (substl [M1,...,Mn] c) which substitutes in parallel
+ M1,...,Mn for respectively Rel(1),...,Rel(n) in c *)
+
+(* 1st : general case *)
+
+type info = Closed | Open | Unknown
+type 'a substituend = { mutable sinfo: info; sit: 'a }
+
+let rec lift_substituend depth s =
+ match s.sinfo with
+ | Closed -> s.sit
+ | Open -> lift depth s.sit
+ | Unknown ->
+ s.sinfo <- if closed0 s.sit then Closed else Open;
+ lift_substituend depth s
+
+let make_substituend c = { sinfo=Unknown; sit=c }
+
+let substn_many lamv n =
+ let lv = Array.length lamv in
+ let rec substrec depth = function
+ | Rel k as x ->
+ if k<=depth then
+ x
+ else if k-depth <= lv then
+ lift_substituend depth lamv.(k-depth-1)
+ else
+ Rel (k-lv)
+ | VAR id -> VAR id
+ | DOPN(oper,cl) -> DOPN(oper,Array.map (substrec depth) cl)
+ | DOPL(oper,cl) -> DOPL(oper,List.map (substrec depth) cl)
+ | DOP1(oper,c) -> DOP1(oper,substrec depth c)
+ | DOP2(oper,c1,c2) -> DOP2(oper,substrec depth c1,substrec depth c2)
+ | DLAM(na,c) -> DLAM(na,substrec (depth+1) c)
+ | DLAMV(na,v) -> DLAMV(na,Array.map (substrec (depth+1)) v)
+ | x -> x
+ in
+ substrec n
+
+let substl laml =
+ substn_many (Array.map make_substituend (Array.of_list laml)) 0
+let subst1 lam = substl [lam]
+let pop t = lift (-1) t
+
+
+(* Various occurs checks *)
+
+let occur_opern s =
+ let rec occur_rec = function
+ | DOPN(oper,cl) -> s=oper or (array_exists occur_rec cl)
+ | DOPL(oper,cl) -> s=oper or (List.exists occur_rec cl)
+ | VAR _ -> false
+ | DOP1(_,c) -> occur_rec c
+ | DOP2(_,c1,c2) -> (occur_rec c1) or (occur_rec c2)
+ | DLAM(_,c) -> occur_rec c
+ | DLAMV(_,v) -> array_exists occur_rec v
+ | _ -> false
+ in
+ occur_rec
+
+let occur_oper0 s =
+ let rec occur_rec = function
+ | DOPN(_,cl) -> (array_exists occur_rec cl)
+ | DOPL(_,cl) -> (List.exists occur_rec cl)
+ | DOP0 oper -> s=oper
+ | VAR _ -> false
+ | DOP1(_,c) -> occur_rec c
+ | DOP2(_,c1,c2) -> (occur_rec c1) or (occur_rec c2)
+ | DLAM(_,c) -> occur_rec c
+ | DLAMV(_,v) -> array_exists occur_rec v
+ | _ -> false
+ in
+ occur_rec
+
+let occur_var s =
+ let rec occur_rec = function
+ | DOPN(_,cl) -> array_exists occur_rec cl
+ | DOPL(_,cl) -> List.exists occur_rec cl
+ | VAR id -> s=id
+ | DOP1(_,c) -> occur_rec c
+ | DOP2(_,c1,c2) -> (occur_rec c1) or (occur_rec c2)
+ | DLAM(_,c) -> occur_rec c
+ | DLAMV(_,v) -> array_exists occur_rec v
+ | _ -> false
+ in
+ occur_rec
+
+let occur_oper s =
+ let rec occur_rec = function
+ | DOPN(oper,cl) -> s=oper or (array_exists occur_rec cl)
+ | DOPL(oper,cl) -> s=oper or (List.exists occur_rec cl)
+ | VAR _ -> false
+ | DOP0 oper -> s=oper
+ | DOP1(oper,c) -> s=oper or occur_rec c
+ | DOP2(oper,c1,c2) -> s=oper or (occur_rec c1) or (occur_rec c2)
+ | DLAM(_,c) -> occur_rec c
+ | DLAMV(_,v) -> array_exists occur_rec v
+ | _ -> false
+ in
+ occur_rec
+
+(* Returns the list of global variables in a term *)
+
+let global_varsl l constr =
+ let rec filtrec acc = function
+ | VAR id -> id::acc
+ | DOP1(oper,c) -> filtrec acc c
+ | DOP2(oper,c1,c2) -> filtrec (filtrec acc c1) c2
+ | DOPN(oper,cl) -> Array.fold_left filtrec acc cl
+ | DOPL(oper,cl) -> List.fold_left filtrec acc cl
+ | DLAM(_,c) -> filtrec acc c
+ | DLAMV(_,v) -> Array.fold_left filtrec acc v
+ | _ -> acc
+ in
+ filtrec l constr
+
+let global_vars constr = global_varsl [] constr
+
+let global_vars_set constr =
+ List.fold_left (fun s x -> Idset.add x s) Idset.empty (global_vars constr)
+
+(* alpha equality for generic terms : checks first if M and M' are equal,
+ otherwise checks equality forgetting the name annotation of DLAM and DLAMV*)
+
+let rec eq_term m m' =
+ (m == m')
+ or (m = m')
+ or (match (m,m') with
+ | (DOP1(oper1,c1),DOP1(oper2,c2)) ->
+ oper1 = oper2 & eq_term c1 c2
+ | (DOP2(oper1,c1,t1),DOP2(oper2,c2,t2)) ->
+ oper1 = oper2 & eq_term c1 c2 & eq_term t1 t2
+ | (DOPN(oper1,cl1),DOPN(oper2,cl2)) ->
+ oper1 = oper2 & array_for_all2 eq_term cl1 cl2
+ | (DOPL(oper1,cl1),DOPL(oper2,cl2)) ->
+ oper1 = oper2 & List.for_all2 eq_term cl1 cl2
+ | (DLAM(_,c1),DLAM(_,c2)) -> eq_term c1 c2
+ | (DLAMV(_,cl1),DLAMV(_,cl2)) -> array_for_all2 eq_term cl1 cl2
+ | _ -> false)
+
+(* (dependent M N) is true iff M is eq_term with a subterm of N
+ M is appropriately lifted through abstractions of N *)
+let dependent =
+ let rec deprec m = function t ->
+ (eq_term m t)
+ or (match t with
+ | VAR _ -> false
+ | DOP1(_,c) -> deprec m c
+ | DOP2(_,c,t) -> deprec m c or deprec m t
+ | DOPN(_,cl) -> array_exists (deprec m) cl
+ | DOPL(_,cl) -> List.exists (deprec m) cl
+ | DLAM(_,c) -> deprec (lift1 m) c
+ | DLAMV(_,v) -> array_exists (deprec (lift1 m)) v
+ | _ -> false)
+ in
+ deprec
+
+(* (thin_val sigma) removes identity substitutions from sigma *)
+
+let rec thin_val = function
+ | [] -> []
+ | (((id,{sit=VAR id'}) as s)::tl) ->
+ if id = id' then thin_val tl else s::(thin_val tl)
+ | h::tl -> h::(thin_val tl)
+
+(* (replace_vars sigma M) applies substitution sigma to term M *)
+let replace_vars var_alist =
+ let var_alist = thin_val var_alist in
+ let rec substrec n = function
+ | (VAR(x) as c) ->
+ (try lift_substituend n (List.assoc x var_alist)
+ with Not_found -> c)
+
+ | DOPN(oper,cl) -> DOPN(oper,Array.map (substrec n) cl)
+ | DOPL(oper,cl) -> DOPL(oper,List.map (substrec n) cl)
+ | DOP1(oper,c) -> DOP1(oper,substrec n c)
+ | DOP2(oper,c1,c2) -> DOP2(oper,substrec n c1,substrec n c2)
+ | DLAM(na,c) -> DLAM(na,substrec (n+1) c)
+ | DLAMV(na,v) -> DLAMV(na,Array.map (substrec (n+1)) v)
+ | x -> x
+ in
+ if var_alist = [] then (function x -> x) else substrec 0
+
+let subst_varn str n = replace_vars [(str,make_substituend (Rel n))]
+
+(* (subst_var str t) substitute (VAR str) by (Rel 1) in t *)
+let subst_var str = subst_varn str 1
+
+
+(* renames different ocurrences of (VAR id) in t with a fresh identifier
+ wrt. acc *)
+let rename_diff_occ id acc t =
+ let rec rename_occ acc = function
+ | (VAR(x) as c) ->
+ if x <> id then
+ acc,c
+ else
+ let nid = next_ident_away id acc in (nid::acc), (VAR nid)
+ | DOPN(oper,cl) ->
+ let nacc,ncl = vrename_occ acc cl in nacc,DOPN(oper, ncl)
+ | DOPL(oper,cl) ->
+ let nacc,ncl = lrename_occ acc cl in nacc, DOPL(oper,ncl)
+ | DOP1(oper,c) ->
+ let nacc,nc = rename_occ acc c in nacc, DOP1(oper,nc)
+ | DOP2(oper,c1,c2) ->
+ let nacc,nc1 = rename_occ acc c1 in
+ let nacc2,nc2 = rename_occ nacc c2 in
+ nacc2, DOP2(oper,nc1,nc2)
+ | DLAM(na,c) ->
+ let nacc,nc = rename_occ acc c in (nacc, DLAM(na,nc))
+ | DLAMV(na,v) ->
+ let nacc,nv = vrename_occ acc v in (nacc, DLAMV(na, nv))
+ | x -> acc,x
+ and lrename_occ acc = function
+ | [] -> acc,[]
+ | (t::lt) ->
+ let nacc,nt = rename_occ acc t in
+ let nacc2,nlt = lrename_occ nacc lt
+ in nacc2,(nt::nlt)
+ and vrename_occ acc v =
+ let nacc,nl = lrename_occ acc (Array.to_list v)
+ in nacc, Array.of_list nl
+ in
+ rename_occ acc t
+
+
+let sAPP c n =
+ match c with
+ | DLAM(na,m) -> subst1 n m
+ | _ -> invalid_arg "SAPP"
+
+let sAPPV c n =
+ match c with
+ | DLAMV(na,mV) -> Array.map (subst1 n) mV
+ | _ -> invalid_arg "SAPPV"
+
+let sAPPVi i c n =
+ match c with
+ | DLAMV(na,mV) -> subst1 n mV.(i)
+ | _ -> invalid_arg "SAPPVi"
+
+let sAPPList constr cl =
+ let rec srec stack = function
+ | (DLAM(_,c), (h::t)) -> srec (h::stack) (c,t)
+ | (c, []) -> substl stack c
+ | (_, _) -> failwith "SAPPList"
+ in
+ srec [] (constr,cl)
+
+let sAPPVList constr cl =
+ let rec srec stack = function
+ | (DLAM(_,c), (h::t)) -> srec (h::stack) (c,t)
+ | (DLAMV(_,c), [h]) -> Array.map (substl (h::stack)) c
+ | (_, _) -> failwith "SAPPVList"
+ in
+ srec [] (constr,cl)
+
+let sAPPViList i constr cl=
+ let rec srec stack = function
+ | (DLAM(_,c), (h::t)) -> srec (h::stack) (c,t)
+ | (DLAMV(_,c), [h]) -> substl (h::stack) c.(i)
+ | (_, _) -> failwith "SAPPViList"
+ in
+ srec [] (constr,cl)
+
+let under_dlams f =
+ let rec apprec = function
+ | DLAMV(na,c) -> DLAMV(na,Array.map f c)
+ | DLAM(na,c) -> DLAM(na,apprec c)
+ | _ -> failwith "under_dlams"
+ in
+ apprec
+
+
+(* utility for discharge *)
+type modification_action = ABSTRACT | ERASE
+
+let interp_modif absfun oper (oper',modif) cl =
+ let rec interprec = function
+ | ([], cl) -> DOPN(oper',Array.of_list cl)
+ | (ERASE::tlm, c::cl) -> interprec (tlm,cl)
+ | (ABSTRACT::tlm, c::cl) -> absfun (interprec (tlm,cl)) c
+ | _ -> assert false
+ in
+ interprec (modif,cl)
+
+
+type 'a modification =
+ | NOT_OCCUR
+ | DO_ABSTRACT of 'a * modification_action list
+ | DO_REPLACE
+
+let modify_opers replfun absfun oper_alist =
+ let failure () =
+ anomalylabstrm "generic__modify_opers"
+ [< 'sTR"An oper which was never supposed to appear has just appeared" ;
+ 'sPC ; 'sTR"Either this is in system code, and you need to" ; 'sPC;
+ 'sTR"report this error," ; 'sPC ;
+ 'sTR"Or you are using a user-written tactic which calls" ; 'sPC ;
+ 'sTR"generic__modify_opers, in which case the user-written code" ;
+ 'sPC ; 'sTR"is broken - this function is an internal system" ;
+ 'sPC ; 'sTR"for internal system use only" >]
+ in
+ let rec substrec = function
+ | DOPN(oper,cl) as c ->
+ let cl' = Array.map substrec cl in
+ (try
+ (match List.assoc oper oper_alist with
+ | NOT_OCCUR -> failure ()
+ | DO_ABSTRACT (oper',modif) ->
+ if List.length modif > Array.length cl then
+ anomaly "found a reference with too few args"
+ else
+ interp_modif absfun oper (oper',modif) (Array.to_list cl')
+ | DO_REPLACE -> substrec (replfun (DOPN(oper,cl'))))
+ with
+ | Not_found -> DOPN(oper,cl'))
+ | DOP1(i,c) -> DOP1(i,substrec c)
+ | DOPL(oper,cl) -> DOPL(oper,List.map substrec cl)
+ | DOP2(oper,c1,c2) -> DOP2(oper,substrec c1,substrec c2)
+ | DLAM(na,c) -> DLAM(na,substrec c)
+ | DLAMV(na,v) -> DLAMV(na,Array.map substrec v)
+ | x -> x
+ in
+ if oper_alist = [] then fun x -> x else substrec
+
+let put_DLAMSV lna lc =
+ match lna with
+ | [] -> anomaly "put_DLAM"
+ | na::lrest -> List.fold_left (fun c na -> DLAM(na,c)) (DLAMV(na,lc)) lrest
+
+let put_DLAMSV_subst lid lc =
+ match lid with
+ | [] -> anomaly "put_DLAM"
+ | id::lrest ->
+ List.fold_left (fun c id' -> DLAM(Name id',subst_var id' c))
+ (DLAMV(Name id,Array.map (subst_var id) lc)) lrest
+
+let rec decomp_DLAMV n = function
+ | DLAM(_,lc) -> decomp_DLAMV (n-1) lc
+ | DLAMV(_,lc) -> if n = 1 then lc else error "decomp_DLAMV 0"
+ | _ -> error "decomp_DLAMV 1"
+
+let decomp_DLAMV_name n =
+ let rec decomprec lna n = function
+ | DLAM(na,lc) -> decomprec (na::lna) (pred n) lc
+ | DLAMV(na,lc) -> if n = 1 then (na::lna,lc) else error "decomp_DLAMV 0"
+ | _ -> error "decomp_DLAMV 1"
+ in
+ decomprec [] n
+
+let decomp_all_DLAMV_name constr =
+ let rec decomprec lna = function
+ | DLAM(na,lc) -> decomprec (na::lna) lc
+ | DLAMV(na,lc) -> (na::lna,lc)
+ | _ -> assert false
+ in
+ decomprec [] constr
+
+
+(* [Rel (n+m);...;Rel(n+1)] *)
+
+let rel_vect n m = Array.init m (fun i -> Rel(n+m-i))
+
+let rel_list n m =
+ let rec reln l p =
+ if p>m then l else reln (Rel(n+p)::l) (p+1)
+ in
+ reln [] 1
+
+
+(* Hash-consing *)
+let comp_term t1 t2 =
+ match (t1,t2) with
+ | (DOP0 o1, DOP0 o2) -> o1==o2
+ | (DOP1(o1,t1), DOP1(o2,t2)) -> o1==o2 & t1==t2
+ | (DOP2(o1,t1,u1), DOP2(o2,t2,u2)) -> o1==o2 & t1==t2 & u1==u2
+ | (DOPN(o1,v1), DOPN(o2,v2)) ->
+ (o1==o2) & (Array.length v1 = Array.length v2)
+ & array_for_all2 (==) v1 v2
+ | (DOPL(o1,l1), DOPL(o2,l2)) ->
+ (o1==o2) & (List.length l1 = List.length l2)
+ & List.for_all2 (==) l1 l2
+ | (DLAM(x1,t1), DLAM(x2,t2)) -> x1==x2 & t1==t2
+ | (DLAMV(x1,v1), DLAMV(x2,v2)) ->
+ (x1==x2) & (Array.length v1 = Array.length v2)
+ & array_for_all2 (==) v1 v2
+ | (Rel i, Rel j) -> i=j
+ | (VAR x, VAR y) -> x==y
+ | _ -> false
+
+let hash_term (sh_rec,(sh_op,sh_na,sh_id)) t =
+ match t with
+ | DOP0 o -> DOP0 (sh_op o)
+ | DOP1(o,t) -> DOP1(sh_op o, sh_rec t)
+ | DOP2(o,t1,t2) -> DOP2(sh_op o, sh_rec t1, sh_rec t2)
+ | DOPN(o,v) -> DOPN(sh_op o, Array.map sh_rec v)
+ | DOPL(o,l) -> DOPL(sh_op o, List.map sh_rec l)
+ | DLAM(n,t) -> DLAM(sh_na n, sh_rec t)
+ | DLAMV(n,v) -> DLAMV(sh_na n, Array.map sh_rec v)
+ | Rel i -> t
+ | VAR x -> VAR (sh_id x)