]> matita.cs.unibo.it Git - helm.git/blob - helm/gTopLevel/proofEngineReduction.ml
1b36e686e4337da522ce688450316af2ce94e4b4
[helm.git] / helm / gTopLevel / proofEngineReduction.ml
1 (* Copyright (C) 2002, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26 (******************************************************************************)
27 (*                                                                            *)
28 (*                               PROJECT HELM                                 *)
29 (*                                                                            *)
30 (*                Claudio Sacerdoti Coen <sacerdot@cs.unibo.it>               *)
31 (*                                 12/04/2002                                 *)
32 (*                                                                            *)
33 (*                                                                            *)
34 (******************************************************************************)
35
36
37 (* The code of this module is derived from the code of CicReduction *)
38
39 exception Impossible of int;;
40 exception ReferenceToConstant;;
41 exception ReferenceToVariable;;
42 exception ReferenceToCurrentProof;;
43 exception ReferenceToInductiveDefinition;;
44 exception WrongUriToInductiveDefinition;;
45 exception WrongUriToConstant;;
46 exception RelToHiddenHypothesis;;
47
48 let alpha_equivalence =
49  let module C = Cic in
50   let rec aux t t' =
51    if t = t' then true
52    else
53     match t,t' with
54        C.Var (uri1,exp_named_subst1), C.Var (uri2,exp_named_subst2) ->
55         UriManager.eq uri1 uri2 &&
56          aux_exp_named_subst exp_named_subst1 exp_named_subst2
57      | C.Cast (te,ty), C.Cast (te',ty') ->
58         aux te te' && aux ty ty'
59      | C.Prod (_,s,t), C.Prod (_,s',t') ->
60         aux s s' && aux t t'
61      | C.Lambda (_,s,t), C.Lambda (_,s',t') ->
62         aux s s' && aux t t'
63      | C.LetIn (_,s,t), C.LetIn(_,s',t') ->
64         aux s s' && aux t t'
65      | C.Appl l, C.Appl l' ->
66         (try
67           List.fold_left2
68            (fun b t1 t2 -> b && aux t1 t2) true l l'
69          with
70           Invalid_argument _ -> false)
71      | C.Const (uri,exp_named_subst1), C.Const (uri',exp_named_subst2) ->
72         UriManager.eq uri uri' &&
73          aux_exp_named_subst exp_named_subst1 exp_named_subst2
74      | C.MutInd (uri,i,exp_named_subst1), C.MutInd (uri',i',exp_named_subst2) ->
75         UriManager.eq uri uri' && i = i' &&
76          aux_exp_named_subst exp_named_subst1 exp_named_subst2
77      | C.MutConstruct (uri,i,j,exp_named_subst1),
78        C.MutConstruct (uri',i',j',exp_named_subst2) ->
79         UriManager.eq uri uri' && i = i' && j = j' &&
80          aux_exp_named_subst exp_named_subst1 exp_named_subst2
81      | C.MutCase (sp,i,outt,t,pl), C.MutCase (sp',i',outt',t',pl') ->
82         UriManager.eq sp sp' && i = i' &&
83          aux outt outt' && aux t t' &&
84           (try
85             List.fold_left2
86              (fun b t1 t2 -> b && aux t1 t2) true pl pl'
87            with
88             Invalid_argument _ -> false)
89      | C.Fix (i,fl), C.Fix (i',fl') ->
90         i = i' &&
91         (try
92           List.fold_left2
93            (fun b (_,i,ty,bo) (_,i',ty',bo') ->
94              b && i = i' && aux ty ty' && aux bo bo'
95            ) true fl fl'
96          with
97           Invalid_argument _ -> false)
98      | C.CoFix (i,fl), C.CoFix (i',fl') ->
99         i = i' &&
100         (try
101           List.fold_left2
102            (fun b (_,ty,bo) (_,ty',bo') ->
103              b && aux ty ty' && aux bo bo'
104            ) true fl fl'
105          with
106           Invalid_argument _ -> false)
107      | _,_ -> false (* we already know that t != t' *)
108   and aux_exp_named_subst exp_named_subst1 exp_named_subst2 =
109    try
110      List.fold_left2
111       (fun b (uri1,t1) (uri2,t2) ->
112         b && UriManager.eq uri1 uri2 && aux t1 t2
113       ) true exp_named_subst1 exp_named_subst2
114     with
115      Invalid_argument _ -> false
116   in
117    aux
118 ;;
119
120 (* "textual" replacement of a subterm with another one *)
121 let replace ~equality ~what ~with_what ~where =
122  let module C = Cic in
123   let rec aux =
124    function
125       t when (equality t what) -> with_what
126     | C.Rel _ as t -> t
127     | C.Var (uri,exp_named_subst) ->
128        C.Var (uri,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
129     | C.Meta _ as t -> t
130     | C.Sort _ as t -> t
131     | C.Implicit as t -> t
132     | C.Cast (te,ty) -> C.Cast (aux te, aux ty)
133     | C.Prod (n,s,t) -> C.Prod (n, aux s, aux t)
134     | C.Lambda (n,s,t) -> C.Lambda (n, aux s, aux t)
135     | C.LetIn (n,s,t) -> C.LetIn (n, aux s, aux t)
136     | C.Appl l ->
137        (* Invariant enforced: no application of an application *)
138        (match List.map aux l with
139            (C.Appl l')::tl -> C.Appl (l'@tl)
140          | l' -> C.Appl l')
141     | C.Const (uri,exp_named_subst) ->
142        C.Const (uri,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
143     | C.MutInd (uri,i,exp_named_subst) ->
144        C.MutInd
145         (uri,i,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
146     | C.MutConstruct (uri,i,j,exp_named_subst) ->
147        C.MutConstruct
148         (uri,i,j,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
149     | C.MutCase (sp,i,outt,t,pl) ->
150        C.MutCase (sp,i,aux outt, aux t,List.map aux pl)
151     | C.Fix (i,fl) ->
152        let substitutedfl =
153         List.map
154          (fun (name,i,ty,bo) -> (name, i, aux ty, aux bo))
155           fl
156        in
157         C.Fix (i, substitutedfl)
158     | C.CoFix (i,fl) ->
159        let substitutedfl =
160         List.map
161          (fun (name,ty,bo) -> (name, aux ty, aux bo))
162           fl
163        in
164         C.CoFix (i, substitutedfl)
165   in
166    aux where
167 ;;
168
169 (* replaces in a term a term with another one. *)
170 (* Lifting are performed as usual.             *)
171 let replace_lifting ~equality ~what ~with_what ~where =
172  let rec substaux k what =
173   let module C = Cic in
174   let module S = CicSubstitution in
175    function
176       t when (equality t what) -> S.lift (k-1) with_what
177     | C.Rel n as t -> t
178     | C.Var (uri,exp_named_subst) ->
179        let exp_named_subst' =
180         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
181        in
182         C.Var (uri,exp_named_subst')
183     | C.Meta (i, l) as t -> 
184        let l' =
185         List.map
186          (function
187              None -> None
188            | Some t -> Some (substaux k what t)
189          ) l
190        in
191         C.Meta(i,l')
192     | C.Sort _ as t -> t
193     | C.Implicit as t -> t
194     | C.Cast (te,ty) -> C.Cast (substaux k what te, substaux k what ty)
195     | C.Prod (n,s,t) ->
196        C.Prod (n, substaux k what s, substaux (k + 1) (S.lift 1 what) t)
197     | C.Lambda (n,s,t) ->
198        C.Lambda (n, substaux k what s, substaux (k + 1) (S.lift 1 what) t)
199     | C.LetIn (n,s,t) ->
200        C.LetIn (n, substaux k what s, substaux (k + 1) (S.lift 1 what) t)
201     | C.Appl (he::tl) ->
202        (* Invariant: no Appl applied to another Appl *)
203        let tl' = List.map (substaux k what) tl in
204         begin
205          match substaux k what he with
206             C.Appl l -> C.Appl (l@tl')
207           | _ as he' -> C.Appl (he'::tl')
208         end
209     | C.Appl _ -> assert false
210     | C.Const (uri,exp_named_subst) ->
211        let exp_named_subst' =
212         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
213        in
214        C.Const (uri,exp_named_subst')
215     | C.MutInd (uri,i,exp_named_subst) ->
216        let exp_named_subst' =
217         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
218        in
219         C.MutInd (uri,i,exp_named_subst')
220     | C.MutConstruct (uri,i,j,exp_named_subst) ->
221        let exp_named_subst' =
222         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
223        in
224         C.MutConstruct (uri,i,j,exp_named_subst')
225     | C.MutCase (sp,i,outt,t,pl) ->
226        C.MutCase (sp,i,substaux k what outt, substaux k what t,
227         List.map (substaux k what) pl)
228     | C.Fix (i,fl) ->
229        let len = List.length fl in
230        let substitutedfl =
231         List.map
232          (fun (name,i,ty,bo) ->
233            (name, i, substaux k what ty, substaux (k+len) (S.lift len what) bo))
234           fl
235        in
236         C.Fix (i, substitutedfl)
237     | C.CoFix (i,fl) ->
238        let len = List.length fl in
239        let substitutedfl =
240         List.map
241          (fun (name,ty,bo) ->
242            (name, substaux k what ty, substaux (k+len) (S.lift len what) bo))
243           fl
244        in
245         C.CoFix (i, substitutedfl)
246  in
247   substaux 1 what where
248 ;;
249
250 (* Takes a well-typed term and fully reduces it. *)
251 (*CSC: It does not perform reduction in a Case *)
252 let reduce context =
253  let rec reduceaux context l =
254   let module C = Cic in
255   let module S = CicSubstitution in
256    function
257       C.Rel n as t ->
258        (match List.nth context (n-1) with
259            Some (_,C.Decl _) -> if l = [] then t else C.Appl (t::l)
260          | Some (_,C.Def bo) -> reduceaux context l (S.lift n bo)
261          | None -> raise RelToHiddenHypothesis
262        )
263     | C.Var (uri,exp_named_subst) ->
264        let exp_named_subst' =
265         reduceaux_exp_named_subst context l exp_named_subst
266        in
267        (match CicEnvironment.get_obj uri with
268            C.Constant _ -> raise ReferenceToConstant
269          | C.CurrentProof _ -> raise ReferenceToCurrentProof
270          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
271          | C.Variable (_,None,_,_) ->
272             let t' = C.Var (uri,exp_named_subst') in
273              if l = [] then t' else C.Appl (t'::l)
274          | C.Variable (_,Some body,_,_) ->
275             (reduceaux context l
276               (CicSubstitution.subst_vars exp_named_subst' body))
277        )
278     | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
279     | C.Sort _ as t -> t (* l should be empty *)
280     | C.Implicit as t -> t
281     | C.Cast (te,ty) ->
282        C.Cast (reduceaux context l te, reduceaux context l ty)
283     | C.Prod (name,s,t) ->
284        assert (l = []) ;
285        C.Prod (name,
286         reduceaux context [] s,
287         reduceaux ((Some (name,C.Decl s))::context) [] t)
288     | C.Lambda (name,s,t) ->
289        (match l with
290            [] ->
291             C.Lambda (name,
292              reduceaux context [] s,
293              reduceaux ((Some (name,C.Decl s))::context) [] t)
294          | he::tl -> reduceaux context tl (S.subst he t)
295            (* when name is Anonimous the substitution should be superfluous *)
296        )
297     | C.LetIn (n,s,t) ->
298        reduceaux context l (S.subst (reduceaux context [] s) t)
299     | C.Appl (he::tl) ->
300        let tl' = List.map (reduceaux context []) tl in
301         reduceaux context (tl'@l) he
302     | C.Appl [] -> raise (Impossible 1)
303     | C.Const (uri,exp_named_subst) ->
304        let exp_named_subst' =
305         reduceaux_exp_named_subst context l exp_named_subst
306        in
307         (match CicEnvironment.get_obj uri with
308             C.Constant (_,Some body,_,_) ->
309              (reduceaux context l
310                (CicSubstitution.subst_vars exp_named_subst' body))
311           | C.Constant (_,None,_,_) ->
312              let t' = C.Const (uri,exp_named_subst') in
313               if l = [] then t' else C.Appl (t'::l)
314           | C.Variable _ -> raise ReferenceToVariable
315           | C.CurrentProof (_,_,body,_,_) ->
316              (reduceaux context l
317                (CicSubstitution.subst_vars exp_named_subst' body))
318           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
319         )
320     | C.MutInd (uri,i,exp_named_subst) ->
321        let exp_named_subst' =
322         reduceaux_exp_named_subst context l exp_named_subst
323        in
324         let t' = C.MutInd (uri,i,exp_named_subst') in
325          if l = [] then t' else C.Appl (t'::l)
326     | C.MutConstruct (uri,i,j,exp_named_subst) as t ->
327        let exp_named_subst' =
328         reduceaux_exp_named_subst context l exp_named_subst
329        in
330         let t' = C.MutConstruct (uri,i,j,exp_named_subst') in
331          if l = [] then t' else C.Appl (t'::l)
332     | C.MutCase (mutind,i,outtype,term,pl) ->
333        let decofix =
334         function
335            C.CoFix (i,fl) as t ->
336             let tys =
337              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
338             in
339              let (_,_,body) = List.nth fl i in
340               let body' =
341                let counter = ref (List.length fl) in
342                 List.fold_right
343                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
344                  fl
345                  body
346               in
347                reduceaux context [] body'
348          | C.Appl (C.CoFix (i,fl) :: tl) ->
349             let tys =
350              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
351             in
352              let (_,_,body) = List.nth fl i in
353               let body' =
354                let counter = ref (List.length fl) in
355                 List.fold_right
356                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
357                  fl
358                  body
359               in
360                let tl' = List.map (reduceaux context []) tl in
361                 reduceaux context tl' body'
362          | t -> t
363        in
364         (match decofix (reduceaux context [] term) with
365             C.MutConstruct (_,_,j,_) -> reduceaux context l (List.nth pl (j-1))
366           | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
367              let (arity, r) =
368               match CicEnvironment.get_obj mutind with
369                  C.InductiveDefinition (tl,_,r) ->
370                    let (_,_,arity,_) = List.nth tl i in
371                     (arity,r)
372                | _ -> raise WrongUriToInductiveDefinition
373              in
374               let ts =
375                let rec eat_first =
376                 function
377                    (0,l) -> l
378                  | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
379                  | _ -> raise (Impossible 5)
380                in
381                 eat_first (r,tl)
382               in
383                reduceaux context (ts@l) (List.nth pl (j-1))
384          | C.Cast _ | C.Implicit ->
385             raise (Impossible 2) (* we don't trust our whd ;-) *)
386          | _ ->
387            let outtype' = reduceaux context [] outtype in
388            let term' = reduceaux context [] term in
389            let pl' = List.map (reduceaux context []) pl in
390             let res =
391              C.MutCase (mutind,i,outtype',term',pl')
392             in
393              if l = [] then res else C.Appl (res::l)
394        )
395     | C.Fix (i,fl) ->
396        let tys =
397         List.map (function (name,_,ty,_) -> Some (C.Name name, C.Decl ty)) fl
398        in
399         let t' () =
400          let fl' =
401           List.map
402            (function (n,recindex,ty,bo) ->
403              (n,recindex,reduceaux context [] ty, reduceaux (tys@context) [] bo)
404            ) fl
405          in
406           C.Fix (i, fl')
407         in
408          let (_,recindex,_,body) = List.nth fl i in
409           let recparam =
410            try
411             Some (List.nth l recindex)
412            with
413             _ -> None
414           in
415            (match recparam with
416                Some recparam ->
417                 (match reduceaux context [] recparam with
418                     C.MutConstruct _
419                   | C.Appl ((C.MutConstruct _)::_) ->
420                      let body' =
421                       let counter = ref (List.length fl) in
422                        List.fold_right
423                         (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
424                         fl
425                         body
426                      in
427                       (* Possible optimization: substituting whd recparam in l*)
428                       reduceaux context l body'
429                   | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
430                 )
431              | None -> if l = [] then t' () else C.Appl ((t' ())::l)
432            )
433     | C.CoFix (i,fl) ->
434        let tys =
435         List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
436        in
437         let t' =
438          let fl' =
439           List.map
440            (function (n,ty,bo) ->
441              (n,reduceaux context [] ty, reduceaux (tys@context) [] bo)
442            ) fl
443          in
444           C.CoFix (i, fl')
445         in
446          if l = [] then t' else C.Appl (t'::l)
447  and reduceaux_exp_named_subst context l =
448   List.map (function uri,t -> uri,reduceaux context [] t)
449  in
450   reduceaux context []
451 ;;
452
453 exception WrongShape;;
454 exception AlreadySimplified;;
455
456 (* Takes a well-typed term and                                               *)
457 (*  1) Performs beta-iota-zeta reduction until delta reduction is needed     *)
458 (*  2) Attempts delta-reduction. If the residual is a Fix lambda-abstracted  *)
459 (*     w.r.t. zero or more variables and if the Fix can be reduced, than it  *)
460 (*     is reduced, the delta-reduction is succesfull and the whole algorithm *)
461 (*     is applied again to the new redex; Step 3) is applied to the result   *)
462 (*     of the recursive simplification. Otherwise, if the Fix can not be     *)
463 (*     reduced, than the delta-reductions fails and the delta-redex is       *)
464 (*     not reduced. Otherwise, if the delta-residual is not the              *)
465 (*     lambda-abstraction of a Fix, then it is reduced and the result is     *)
466 (*     directly returned, without performing step 3).                        *) 
467 (*  3) Folds the application of the constant to the arguments that did not   *)
468 (*     change in every iteration, i.e. to the actual arguments for the       *)
469 (*     lambda-abstractions that precede the Fix.                             *)
470 (*CSC: It does not perform simplification in a Case *)
471 let simpl context =
472  (* reduceaux is equal to the reduceaux locally defined inside *)
473  (* reduce, but for the const case.                            *) 
474  (**** Step 1 ****)
475  let rec reduceaux context l =
476   let module C = Cic in
477   let module S = CicSubstitution in
478    function
479       C.Rel n as t ->
480        (match List.nth context (n-1) with
481            Some (_,C.Decl _) -> if l = [] then t else C.Appl (t::l)
482          | Some (_,C.Def bo) ->
483             try_delta_expansion l t (S.lift n bo)
484          | None -> raise RelToHiddenHypothesis
485        )
486     | C.Var (uri,exp_named_subst) ->
487        let exp_named_subst' =
488         reduceaux_exp_named_subst context l exp_named_subst
489        in
490         (match CicEnvironment.get_obj uri with
491             C.Constant _ -> raise ReferenceToConstant
492           | C.CurrentProof _ -> raise ReferenceToCurrentProof
493           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
494           | C.Variable (_,None,_,_) ->
495             let t' = C.Var (uri,exp_named_subst') in
496              if l = [] then t' else C.Appl (t'::l)
497           | C.Variable (_,Some body,_,_) ->
498              reduceaux context l
499               (CicSubstitution.subst_vars exp_named_subst' body)
500         )
501     | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
502     | C.Sort _ as t -> t (* l should be empty *)
503     | C.Implicit as t -> t
504     | C.Cast (te,ty) ->
505        C.Cast (reduceaux context l te, reduceaux context l ty)
506     | C.Prod (name,s,t) ->
507        assert (l = []) ;
508        C.Prod (name,
509         reduceaux context [] s,
510         reduceaux ((Some (name,C.Decl s))::context) [] t)
511     | C.Lambda (name,s,t) ->
512        (match l with
513            [] ->
514             C.Lambda (name,
515              reduceaux context [] s,
516              reduceaux ((Some (name,C.Decl s))::context) [] t)
517          | he::tl -> reduceaux context tl (S.subst he t)
518            (* when name is Anonimous the substitution should be superfluous *)
519        )
520     | C.LetIn (n,s,t) ->
521        reduceaux context l (S.subst (reduceaux context [] s) t)
522     | C.Appl (he::tl) ->
523        let tl' = List.map (reduceaux context []) tl in
524         reduceaux context (tl'@l) he
525     | C.Appl [] -> raise (Impossible 1)
526     | C.Const (uri,exp_named_subst) ->
527        let exp_named_subst' =
528         reduceaux_exp_named_subst context l exp_named_subst
529        in
530         (match CicEnvironment.get_obj uri with
531            C.Constant (_,Some body,_,_) ->
532             try_delta_expansion l
533              (C.Const (uri,exp_named_subst'))
534              (CicSubstitution.subst_vars exp_named_subst' body)
535          | C.Constant (_,None,_,_) ->
536             let t' = C.Const (uri,exp_named_subst') in
537              if l = [] then t' else C.Appl (t'::l)
538          | C.Variable _ -> raise ReferenceToVariable
539          | C.CurrentProof (_,_,body,_,_) -> reduceaux context l body
540          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
541        )
542     | C.MutInd (uri,i,exp_named_subst) ->
543        let exp_named_subst' =
544         reduceaux_exp_named_subst context l exp_named_subst
545        in
546         let t' = C.MutInd (uri,i,exp_named_subst') in
547          if l = [] then t' else C.Appl (t'::l)
548     | C.MutConstruct (uri,i,j,exp_named_subst) ->
549        let exp_named_subst' =
550         reduceaux_exp_named_subst context l exp_named_subst
551        in
552         let t' = C.MutConstruct(uri,i,j,exp_named_subst') in
553          if l = [] then t' else C.Appl (t'::l)
554     | C.MutCase (mutind,i,outtype,term,pl) ->
555        let decofix =
556         function
557            C.CoFix (i,fl) as t ->
558             let tys =
559              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl            in
560              let (_,_,body) = List.nth fl i in
561               let body' =
562                let counter = ref (List.length fl) in
563                 List.fold_right
564                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
565                  fl
566                  body
567               in
568                reduceaux context [] body'
569          | C.Appl (C.CoFix (i,fl) :: tl) ->
570             let tys =
571              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl            in
572              let (_,_,body) = List.nth fl i in
573               let body' =
574                let counter = ref (List.length fl) in
575                 List.fold_right
576                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
577                  fl
578                  body
579               in
580                let tl' = List.map (reduceaux context []) tl in
581                 reduceaux context tl body'
582          | t -> t
583        in
584         (match decofix (reduceaux context [] term) with
585             C.MutConstruct (_,_,j,_) -> reduceaux context l (List.nth pl (j-1))
586           | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
587              let (arity, r) =
588               match CicEnvironment.get_obj mutind with
589                  C.InductiveDefinition (tl,ingredients,r) ->
590                    let (_,_,arity,_) = List.nth tl i in
591                     (arity,r)
592                | _ -> raise WrongUriToInductiveDefinition
593              in
594               let ts =
595                let rec eat_first =
596                 function
597                    (0,l) -> l
598                  | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
599                  | _ -> raise (Impossible 5)
600                in
601                 eat_first (r,tl)
602               in
603                reduceaux context (ts@l) (List.nth pl (j-1))
604          | C.Cast _ | C.Implicit ->
605             raise (Impossible 2) (* we don't trust our whd ;-) *)
606          | _ ->
607            let outtype' = reduceaux context [] outtype in
608            let term' = reduceaux context [] term in
609            let pl' = List.map (reduceaux context []) pl in
610             let res =
611              C.MutCase (mutind,i,outtype',term',pl')
612             in
613              if l = [] then res else C.Appl (res::l)
614        )
615     | C.Fix (i,fl) ->
616        let tys =
617         List.map (function (name,_,ty,_) -> Some (C.Name name, C.Decl ty)) fl
618        in
619         let t' () =
620          let fl' =
621           List.map
622            (function (n,recindex,ty,bo) ->
623              (n,recindex,reduceaux context [] ty, reduceaux (tys@context) [] bo)
624            ) fl
625          in
626           C.Fix (i, fl')
627         in
628          let (_,recindex,_,body) = List.nth fl i in
629           let recparam =
630            try
631             Some (List.nth l recindex)
632            with
633             _ -> None
634           in
635            (match recparam with
636                Some recparam ->
637                 (match reduceaux context [] recparam with
638                     C.MutConstruct _
639                   | C.Appl ((C.MutConstruct _)::_) ->
640                      let body' =
641                       let counter = ref (List.length fl) in
642                        List.fold_right
643                         (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
644                         fl
645                         body
646                      in
647                       (* Possible optimization: substituting whd recparam in l*)
648                       reduceaux context l body'
649                   | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
650                 )
651              | None -> if l = [] then t' () else C.Appl ((t' ())::l)
652            )
653     | C.CoFix (i,fl) ->
654        let tys =
655         List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
656        in
657         let t' =
658          let fl' =
659           List.map
660            (function (n,ty,bo) ->
661              (n,reduceaux context [] ty, reduceaux (tys@context) [] bo)
662            ) fl
663          in
664          C.CoFix (i, fl')
665        in
666          if l = [] then t' else C.Appl (t'::l)
667  and reduceaux_exp_named_subst context l =
668   List.map (function uri,t -> uri,reduceaux context [] t)
669  (**** Step 2 ****)
670  and try_delta_expansion l term body =
671   let module C = Cic in
672   let module S = CicSubstitution in
673    try
674     let res,constant_args =
675      let rec aux rev_constant_args l =
676       function
677          C.Lambda (name,s,t) as t' ->
678           begin
679            match l with
680               [] -> raise WrongShape
681             | he::tl ->
682                (* when name is Anonimous the substitution should *)
683                (* be superfluous                                 *)
684                aux (he::rev_constant_args) tl (S.subst he t)
685           end
686        | C.LetIn (_,s,t) ->
687           aux rev_constant_args l (S.subst s t)
688        | C.Fix (i,fl) as t ->
689           let tys =
690            List.map (function (name,_,ty,_) ->
691             Some (C.Name name, C.Decl ty)) fl
692           in
693            let (_,recindex,_,body) = List.nth fl i in
694             let recparam =
695              try
696               List.nth l recindex
697              with
698               _ -> raise AlreadySimplified
699             in
700              (match CicReduction.whd context recparam with
701                  C.MutConstruct _
702                | C.Appl ((C.MutConstruct _)::_) ->
703                   let body' =
704                    let counter = ref (List.length fl) in
705                     List.fold_right
706                      (function _ ->
707                        decr counter ; S.subst (C.Fix (!counter,fl))
708                      ) fl body
709                   in
710                    (* Possible optimization: substituting whd *)
711                    (* recparam in l                           *)
712                    reduceaux context l body',
713                     List.rev rev_constant_args
714                | _ -> raise AlreadySimplified
715              )
716        | _ -> raise WrongShape
717      in
718       aux [] l body
719     in
720      (**** Step 3 ****)
721      let term_to_fold, delta_expanded_term_to_fold =
722       match constant_args with
723          [] -> term,body
724        | _ -> C.Appl (term::constant_args), C.Appl (body::constant_args)
725      in
726       let simplified_term_to_fold =
727        reduceaux context [] delta_expanded_term_to_fold
728       in
729        replace (=) simplified_term_to_fold term_to_fold res
730    with
731       WrongShape ->
732        (* The constant does not unfold to a Fix lambda-abstracted  *)
733        (* w.r.t. zero or more variables. We just perform reduction.*)
734        reduceaux context l body
735     | AlreadySimplified ->
736        (* If we performed delta-reduction, we would find a Fix   *)
737        (* not applied to a constructor. So, we refuse to perform *)
738        (* delta-reduction.                                       *)
739        if l = [] then term else C.Appl (term::l)
740  in
741   reduceaux context []
742 ;;