]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/tactics/proofEngineReduction.ml
All the reduction tactics have been modified to reduce several (sub)terms
[helm.git] / helm / ocaml / tactics / 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 exception WhatAndWithWhatDoNotHaveTheSameLength;;
121
122 (* "textual" replacement of several subterms with other ones *)
123 let replace ~equality ~what ~with_what ~where =
124  let module C = Cic in
125   let find_image t =
126    let rec find_image_aux =
127     function
128        [],[] -> raise Not_found
129      | what::tl1,with_what::tl2 ->
130         if equality t what then with_what else find_image_aux (tl1,tl2)
131      | _,_ -> raise WhatAndWithWhatDoNotHaveTheSameLength
132    in
133     find_image_aux (what,with_what)
134   in
135   let rec aux t =
136    try
137     find_image t
138    with Not_found ->
139     match t with
140        C.Rel _ -> t
141      | C.Var (uri,exp_named_subst) ->
142         C.Var (uri,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
143      | C.Meta _ -> t
144      | C.Sort _ -> t
145      | C.Implicit as t -> t
146      | C.Cast (te,ty) -> C.Cast (aux te, aux ty)
147      | C.Prod (n,s,t) -> C.Prod (n, aux s, aux t)
148      | C.Lambda (n,s,t) -> C.Lambda (n, aux s, aux t)
149      | C.LetIn (n,s,t) -> C.LetIn (n, aux s, aux t)
150      | C.Appl l ->
151         (* Invariant enforced: no application of an application *)
152         (match List.map aux l with
153             (C.Appl l')::tl -> C.Appl (l'@tl)
154           | l' -> C.Appl l')
155      | C.Const (uri,exp_named_subst) ->
156         C.Const (uri,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
157      | C.MutInd (uri,i,exp_named_subst) ->
158         C.MutInd
159          (uri,i,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
160      | C.MutConstruct (uri,i,j,exp_named_subst) ->
161         C.MutConstruct
162          (uri,i,j,List.map (function (uri,t) -> uri, aux t) exp_named_subst)
163      | C.MutCase (sp,i,outt,t,pl) ->
164         C.MutCase (sp,i,aux outt, aux t,List.map aux pl)
165      | C.Fix (i,fl) ->
166         let substitutedfl =
167          List.map
168           (fun (name,i,ty,bo) -> (name, i, aux ty, aux bo))
169            fl
170         in
171          C.Fix (i, substitutedfl)
172      | C.CoFix (i,fl) ->
173         let substitutedfl =
174          List.map
175           (fun (name,ty,bo) -> (name, aux ty, aux bo))
176            fl
177         in
178          C.CoFix (i, substitutedfl)
179    in
180     aux where
181 ;;
182
183 (* replaces in a term a term with another one. *)
184 (* Lifting are performed as usual.             *)
185 let replace_lifting ~equality ~what ~with_what ~where =
186  let rec substaux k what =
187   let module C = Cic in
188   let module S = CicSubstitution in
189    function
190       t when (equality t what) -> S.lift (k-1) with_what
191     | C.Rel n as t -> t
192     | C.Var (uri,exp_named_subst) ->
193        let exp_named_subst' =
194         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
195        in
196         C.Var (uri,exp_named_subst')
197     | C.Meta (i, l) as t -> 
198        let l' =
199         List.map
200          (function
201              None -> None
202            | Some t -> Some (substaux k what t)
203          ) l
204        in
205         C.Meta(i,l')
206     | C.Sort _ as t -> t
207     | C.Implicit as t -> t
208     | C.Cast (te,ty) -> C.Cast (substaux k what te, substaux k what ty)
209     | C.Prod (n,s,t) ->
210        C.Prod (n, substaux k what s, substaux (k + 1) (S.lift 1 what) t)
211     | C.Lambda (n,s,t) ->
212        C.Lambda (n, substaux k what s, substaux (k + 1) (S.lift 1 what) t)
213     | C.LetIn (n,s,t) ->
214        C.LetIn (n, substaux k what s, substaux (k + 1) (S.lift 1 what) t)
215     | C.Appl (he::tl) ->
216        (* Invariant: no Appl applied to another Appl *)
217        let tl' = List.map (substaux k what) tl in
218         begin
219          match substaux k what he with
220             C.Appl l -> C.Appl (l@tl')
221           | _ as he' -> C.Appl (he'::tl')
222         end
223     | C.Appl _ -> assert false
224     | C.Const (uri,exp_named_subst) ->
225        let exp_named_subst' =
226         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
227        in
228        C.Const (uri,exp_named_subst')
229     | C.MutInd (uri,i,exp_named_subst) ->
230        let exp_named_subst' =
231         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
232        in
233         C.MutInd (uri,i,exp_named_subst')
234     | C.MutConstruct (uri,i,j,exp_named_subst) ->
235        let exp_named_subst' =
236         List.map (function (uri,t) -> uri,substaux k what t) exp_named_subst
237        in
238         C.MutConstruct (uri,i,j,exp_named_subst')
239     | C.MutCase (sp,i,outt,t,pl) ->
240        C.MutCase (sp,i,substaux k what outt, substaux k what t,
241         List.map (substaux k what) pl)
242     | C.Fix (i,fl) ->
243        let len = List.length fl in
244        let substitutedfl =
245         List.map
246          (fun (name,i,ty,bo) ->
247            (name, i, substaux k what ty, substaux (k+len) (S.lift len what) bo))
248           fl
249        in
250         C.Fix (i, substitutedfl)
251     | C.CoFix (i,fl) ->
252        let len = List.length fl in
253        let substitutedfl =
254         List.map
255          (fun (name,ty,bo) ->
256            (name, substaux k what ty, substaux (k+len) (S.lift len what) bo))
257           fl
258        in
259         C.CoFix (i, substitutedfl)
260  in
261   substaux 1 what where
262 ;;
263
264 (* replaces in a term a term with another one. *)
265 (* Lifting are performed as usual.             *)
266 let replace_lifting_csc nnn ~equality ~what ~with_what ~where =
267  let rec substaux k =
268   let module C = Cic in
269   let module S = CicSubstitution in
270    function
271       t when (equality t what) -> S.lift (k-1) with_what
272     | C.Rel n as t ->
273        if n < k then C.Rel n else C.Rel (n + nnn)
274     | C.Var (uri,exp_named_subst) ->
275        let exp_named_subst' =
276         List.map (function (uri,t) -> uri,substaux k t) exp_named_subst
277        in
278         C.Var (uri,exp_named_subst')
279     | C.Meta (i, l) as t -> 
280        let l' =
281         List.map
282          (function
283              None -> None
284            | Some t -> Some (substaux k t)
285          ) l
286        in
287         C.Meta(i,l')
288     | C.Sort _ as t -> t
289     | C.Implicit as t -> t
290     | C.Cast (te,ty) -> C.Cast (substaux k te, substaux k ty)
291     | C.Prod (n,s,t) ->
292        C.Prod (n, substaux k s, substaux (k + 1) t)
293     | C.Lambda (n,s,t) ->
294        C.Lambda (n, substaux k s, substaux (k + 1) t)
295     | C.LetIn (n,s,t) ->
296        C.LetIn (n, substaux k s, substaux (k + 1) t)
297     | C.Appl (he::tl) ->
298        (* Invariant: no Appl applied to another Appl *)
299        let tl' = List.map (substaux k) tl in
300         begin
301          match substaux k he with
302             C.Appl l -> C.Appl (l@tl')
303           | _ as he' -> C.Appl (he'::tl')
304         end
305     | C.Appl _ -> assert false
306     | C.Const (uri,exp_named_subst) ->
307        let exp_named_subst' =
308         List.map (function (uri,t) -> uri,substaux k t) exp_named_subst
309        in
310        C.Const (uri,exp_named_subst')
311     | C.MutInd (uri,i,exp_named_subst) ->
312        let exp_named_subst' =
313         List.map (function (uri,t) -> uri,substaux k t) exp_named_subst
314        in
315         C.MutInd (uri,i,exp_named_subst')
316     | C.MutConstruct (uri,i,j,exp_named_subst) ->
317        let exp_named_subst' =
318         List.map (function (uri,t) -> uri,substaux k t) exp_named_subst
319        in
320         C.MutConstruct (uri,i,j,exp_named_subst')
321     | C.MutCase (sp,i,outt,t,pl) ->
322        C.MutCase (sp,i,substaux k outt, substaux k t,
323         List.map (substaux k) pl)
324     | C.Fix (i,fl) ->
325        let len = List.length fl in
326        let substitutedfl =
327         List.map
328          (fun (name,i,ty,bo) ->
329            (name, i, substaux k ty, substaux (k+len) bo))
330           fl
331        in
332         C.Fix (i, substitutedfl)
333     | C.CoFix (i,fl) ->
334        let len = List.length fl in
335        let substitutedfl =
336         List.map
337          (fun (name,ty,bo) ->
338            (name, substaux k ty, substaux (k+len) bo))
339           fl
340        in
341         C.CoFix (i, substitutedfl)
342  in
343 let res =  
344   substaux 1 where
345 in prerr_endline ("@@@@ risultato replace: " ^ (CicPp.ppterm res)); res
346 ;;
347
348 (* Takes a well-typed term and fully reduces it. *)
349 (*CSC: It does not perform reduction in a Case *)
350 let reduce context =
351  let rec reduceaux context l =
352   let module C = Cic in
353   let module S = CicSubstitution in
354    function
355       C.Rel n as t ->
356        (match List.nth context (n-1) with
357            Some (_,C.Decl _) -> if l = [] then t else C.Appl (t::l)
358          | Some (_,C.Def bo) -> reduceaux context l (S.lift n bo)
359          | None -> raise RelToHiddenHypothesis
360        )
361     | C.Var (uri,exp_named_subst) ->
362        let exp_named_subst' =
363         reduceaux_exp_named_subst context l exp_named_subst
364        in
365        (match CicEnvironment.get_obj uri with
366            C.Constant _ -> raise ReferenceToConstant
367          | C.CurrentProof _ -> raise ReferenceToCurrentProof
368          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
369          | C.Variable (_,None,_,_) ->
370             let t' = C.Var (uri,exp_named_subst') in
371              if l = [] then t' else C.Appl (t'::l)
372          | C.Variable (_,Some body,_,_) ->
373             (reduceaux context l
374               (CicSubstitution.subst_vars exp_named_subst' body))
375        )
376     | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
377     | C.Sort _ as t -> t (* l should be empty *)
378     | C.Implicit as t -> t
379     | C.Cast (te,ty) ->
380        C.Cast (reduceaux context l te, reduceaux context l ty)
381     | C.Prod (name,s,t) ->
382        assert (l = []) ;
383        C.Prod (name,
384         reduceaux context [] s,
385         reduceaux ((Some (name,C.Decl s))::context) [] t)
386     | C.Lambda (name,s,t) ->
387        (match l with
388            [] ->
389             C.Lambda (name,
390              reduceaux context [] s,
391              reduceaux ((Some (name,C.Decl s))::context) [] t)
392          | he::tl -> reduceaux context tl (S.subst he t)
393            (* when name is Anonimous the substitution should be superfluous *)
394        )
395     | C.LetIn (n,s,t) ->
396        reduceaux context l (S.subst (reduceaux context [] s) t)
397     | C.Appl (he::tl) ->
398        let tl' = List.map (reduceaux context []) tl in
399         reduceaux context (tl'@l) he
400     | C.Appl [] -> raise (Impossible 1)
401     | C.Const (uri,exp_named_subst) ->
402        let exp_named_subst' =
403         reduceaux_exp_named_subst context l exp_named_subst
404        in
405         (match CicEnvironment.get_obj uri with
406             C.Constant (_,Some body,_,_) ->
407              (reduceaux context l
408                (CicSubstitution.subst_vars exp_named_subst' body))
409           | C.Constant (_,None,_,_) ->
410              let t' = C.Const (uri,exp_named_subst') in
411               if l = [] then t' else C.Appl (t'::l)
412           | C.Variable _ -> raise ReferenceToVariable
413           | C.CurrentProof (_,_,body,_,_) ->
414              (reduceaux context l
415                (CicSubstitution.subst_vars exp_named_subst' body))
416           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
417         )
418     | C.MutInd (uri,i,exp_named_subst) ->
419        let exp_named_subst' =
420         reduceaux_exp_named_subst context l exp_named_subst
421        in
422         let t' = C.MutInd (uri,i,exp_named_subst') in
423          if l = [] then t' else C.Appl (t'::l)
424     | C.MutConstruct (uri,i,j,exp_named_subst) as t ->
425        let exp_named_subst' =
426         reduceaux_exp_named_subst context l exp_named_subst
427        in
428         let t' = C.MutConstruct (uri,i,j,exp_named_subst') in
429          if l = [] then t' else C.Appl (t'::l)
430     | C.MutCase (mutind,i,outtype,term,pl) ->
431        let decofix =
432         function
433            C.CoFix (i,fl) as t ->
434             let tys =
435              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
436             in
437              let (_,_,body) = List.nth fl i in
438               let body' =
439                let counter = ref (List.length fl) in
440                 List.fold_right
441                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
442                  fl
443                  body
444               in
445                reduceaux context [] body'
446          | C.Appl (C.CoFix (i,fl) :: tl) ->
447             let tys =
448              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
449             in
450              let (_,_,body) = List.nth fl i in
451               let body' =
452                let counter = ref (List.length fl) in
453                 List.fold_right
454                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
455                  fl
456                  body
457               in
458                let tl' = List.map (reduceaux context []) tl in
459                 reduceaux context tl' body'
460          | t -> t
461        in
462         (match decofix (reduceaux context [] term) with
463             C.MutConstruct (_,_,j,_) -> reduceaux context l (List.nth pl (j-1))
464           | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
465              let (arity, r) =
466               match CicEnvironment.get_obj mutind with
467                  C.InductiveDefinition (tl,_,r) ->
468                    let (_,_,arity,_) = List.nth tl i in
469                     (arity,r)
470                | _ -> raise WrongUriToInductiveDefinition
471              in
472               let ts =
473                let rec eat_first =
474                 function
475                    (0,l) -> l
476                  | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
477                  | _ -> raise (Impossible 5)
478                in
479                 eat_first (r,tl)
480               in
481                reduceaux context (ts@l) (List.nth pl (j-1))
482          | C.Cast _ | C.Implicit ->
483             raise (Impossible 2) (* we don't trust our whd ;-) *)
484          | _ ->
485            let outtype' = reduceaux context [] outtype in
486            let term' = reduceaux context [] term in
487            let pl' = List.map (reduceaux context []) pl in
488             let res =
489              C.MutCase (mutind,i,outtype',term',pl')
490             in
491              if l = [] then res else C.Appl (res::l)
492        )
493     | C.Fix (i,fl) ->
494        let tys =
495         List.map (function (name,_,ty,_) -> Some (C.Name name, C.Decl ty)) fl
496        in
497         let t' () =
498          let fl' =
499           List.map
500            (function (n,recindex,ty,bo) ->
501              (n,recindex,reduceaux context [] ty, reduceaux (tys@context) [] bo)
502            ) fl
503          in
504           C.Fix (i, fl')
505         in
506          let (_,recindex,_,body) = List.nth fl i in
507           let recparam =
508            try
509             Some (List.nth l recindex)
510            with
511             _ -> None
512           in
513            (match recparam with
514                Some recparam ->
515                 (match reduceaux context [] recparam with
516                     C.MutConstruct _
517                   | C.Appl ((C.MutConstruct _)::_) ->
518                      let body' =
519                       let counter = ref (List.length fl) in
520                        List.fold_right
521                         (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
522                         fl
523                         body
524                      in
525                       (* Possible optimization: substituting whd recparam in l*)
526                       reduceaux context l body'
527                   | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
528                 )
529              | None -> if l = [] then t' () else C.Appl ((t' ())::l)
530            )
531     | C.CoFix (i,fl) ->
532        let tys =
533         List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
534        in
535         let t' =
536          let fl' =
537           List.map
538            (function (n,ty,bo) ->
539              (n,reduceaux context [] ty, reduceaux (tys@context) [] bo)
540            ) fl
541          in
542           C.CoFix (i, fl')
543         in
544          if l = [] then t' else C.Appl (t'::l)
545  and reduceaux_exp_named_subst context l =
546   List.map (function uri,t -> uri,reduceaux context [] t)
547  in
548   reduceaux context []
549 ;;
550
551 exception WrongShape;;
552 exception AlreadySimplified;;
553
554 (* Takes a well-typed term and                                               *)
555 (*  1) Performs beta-iota-zeta reduction until delta reduction is needed     *)
556 (*  2) Attempts delta-reduction. If the residual is a Fix lambda-abstracted  *)
557 (*     w.r.t. zero or more variables and if the Fix can be reduced, than it  *)
558 (*     is reduced, the delta-reduction is succesfull and the whole algorithm *)
559 (*     is applied again to the new redex; Step 3) is applied to the result   *)
560 (*     of the recursive simplification. Otherwise, if the Fix can not be     *)
561 (*     reduced, than the delta-reductions fails and the delta-redex is       *)
562 (*     not reduced. Otherwise, if the delta-residual is not the              *)
563 (*     lambda-abstraction of a Fix, then it is reduced and the result is     *)
564 (*     directly returned, without performing step 3).                        *) 
565 (*  3) Folds the application of the constant to the arguments that did not   *)
566 (*     change in every iteration, i.e. to the actual arguments for the       *)
567 (*     lambda-abstractions that precede the Fix.                             *)
568 (*CSC: It does not perform simplification in a Case *)
569 let simpl context =
570  (* reduceaux is equal to the reduceaux locally defined inside *)
571  (* reduce, but for the const case.                            *) 
572  (**** Step 1 ****)
573  let rec reduceaux context l =
574   let module C = Cic in
575   let module S = CicSubstitution in
576    function
577       C.Rel n as t ->
578        (match List.nth context (n-1) with
579            Some (_,C.Decl _) -> if l = [] then t else C.Appl (t::l)
580          | Some (_,C.Def bo) ->
581             try_delta_expansion l t (S.lift n bo)
582          | None -> raise RelToHiddenHypothesis
583        )
584     | C.Var (uri,exp_named_subst) ->
585        let exp_named_subst' =
586         reduceaux_exp_named_subst context l exp_named_subst
587        in
588         (match CicEnvironment.get_obj uri with
589             C.Constant _ -> raise ReferenceToConstant
590           | C.CurrentProof _ -> raise ReferenceToCurrentProof
591           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
592           | C.Variable (_,None,_,_) ->
593             let t' = C.Var (uri,exp_named_subst') in
594              if l = [] then t' else C.Appl (t'::l)
595           | C.Variable (_,Some body,_,_) ->
596              reduceaux context l
597               (CicSubstitution.subst_vars exp_named_subst' body)
598         )
599     | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
600     | C.Sort _ as t -> t (* l should be empty *)
601     | C.Implicit as t -> t
602     | C.Cast (te,ty) ->
603        C.Cast (reduceaux context l te, reduceaux context l ty)
604     | C.Prod (name,s,t) ->
605        assert (l = []) ;
606        C.Prod (name,
607         reduceaux context [] s,
608         reduceaux ((Some (name,C.Decl s))::context) [] t)
609     | C.Lambda (name,s,t) ->
610        (match l with
611            [] ->
612             C.Lambda (name,
613              reduceaux context [] s,
614              reduceaux ((Some (name,C.Decl s))::context) [] t)
615          | he::tl -> reduceaux context tl (S.subst he t)
616            (* when name is Anonimous the substitution should be superfluous *)
617        )
618     | C.LetIn (n,s,t) ->
619        reduceaux context l (S.subst (reduceaux context [] s) t)
620     | C.Appl (he::tl) ->
621        let tl' = List.map (reduceaux context []) tl in
622         reduceaux context (tl'@l) he
623     | C.Appl [] -> raise (Impossible 1)
624     | C.Const (uri,exp_named_subst) ->
625        let exp_named_subst' =
626         reduceaux_exp_named_subst context l exp_named_subst
627        in
628         (match CicEnvironment.get_obj uri with
629            C.Constant (_,Some body,_,_) ->
630             try_delta_expansion l
631              (C.Const (uri,exp_named_subst'))
632              (CicSubstitution.subst_vars exp_named_subst' body)
633          | C.Constant (_,None,_,_) ->
634             let t' = C.Const (uri,exp_named_subst') in
635              if l = [] then t' else C.Appl (t'::l)
636          | C.Variable _ -> raise ReferenceToVariable
637          | C.CurrentProof (_,_,body,_,_) -> reduceaux context l body
638          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
639        )
640     | C.MutInd (uri,i,exp_named_subst) ->
641        let exp_named_subst' =
642         reduceaux_exp_named_subst context l exp_named_subst
643        in
644         let t' = C.MutInd (uri,i,exp_named_subst') in
645          if l = [] then t' else C.Appl (t'::l)
646     | C.MutConstruct (uri,i,j,exp_named_subst) ->
647        let exp_named_subst' =
648         reduceaux_exp_named_subst context l exp_named_subst
649        in
650         let t' = C.MutConstruct(uri,i,j,exp_named_subst') in
651          if l = [] then t' else C.Appl (t'::l)
652     | C.MutCase (mutind,i,outtype,term,pl) ->
653        let decofix =
654         function
655            C.CoFix (i,fl) as t ->
656             let tys =
657              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl            in
658              let (_,_,body) = List.nth fl i in
659               let body' =
660                let counter = ref (List.length fl) in
661                 List.fold_right
662                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
663                  fl
664                  body
665               in
666                reduceaux context [] body'
667          | C.Appl (C.CoFix (i,fl) :: tl) ->
668             let tys =
669              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl            in
670              let (_,_,body) = List.nth fl i in
671               let body' =
672                let counter = ref (List.length fl) in
673                 List.fold_right
674                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
675                  fl
676                  body
677               in
678                let tl' = List.map (reduceaux context []) tl in
679                 reduceaux context tl body'
680          | t -> t
681        in
682         (match decofix (reduceaux context [] term) with
683             C.MutConstruct (_,_,j,_) -> reduceaux context l (List.nth pl (j-1))
684           | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
685              let (arity, r) =
686               match CicEnvironment.get_obj mutind with
687                  C.InductiveDefinition (tl,ingredients,r) ->
688                    let (_,_,arity,_) = List.nth tl i in
689                     (arity,r)
690                | _ -> raise WrongUriToInductiveDefinition
691              in
692               let ts =
693                let rec eat_first =
694                 function
695                    (0,l) -> l
696                  | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
697                  | _ -> raise (Impossible 5)
698                in
699                 eat_first (r,tl)
700               in
701                reduceaux context (ts@l) (List.nth pl (j-1))
702          | C.Cast _ | C.Implicit ->
703             raise (Impossible 2) (* we don't trust our whd ;-) *)
704          | _ ->
705            let outtype' = reduceaux context [] outtype in
706            let term' = reduceaux context [] term in
707            let pl' = List.map (reduceaux context []) pl in
708             let res =
709              C.MutCase (mutind,i,outtype',term',pl')
710             in
711              if l = [] then res else C.Appl (res::l)
712        )
713     | C.Fix (i,fl) ->
714        let tys =
715         List.map (function (name,_,ty,_) -> Some (C.Name name, C.Decl ty)) fl
716        in
717         let t' () =
718          let fl' =
719           List.map
720            (function (n,recindex,ty,bo) ->
721              (n,recindex,reduceaux context [] ty, reduceaux (tys@context) [] bo)
722            ) fl
723          in
724           C.Fix (i, fl')
725         in
726          let (_,recindex,_,body) = List.nth fl i in
727           let recparam =
728            try
729             Some (List.nth l recindex)
730            with
731             _ -> None
732           in
733            (match recparam with
734                Some recparam ->
735                 (match reduceaux context [] recparam with
736                     C.MutConstruct _
737                   | C.Appl ((C.MutConstruct _)::_) ->
738                      let body' =
739                       let counter = ref (List.length fl) in
740                        List.fold_right
741                         (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
742                         fl
743                         body
744                      in
745                       (* Possible optimization: substituting whd recparam in l*)
746                       reduceaux context l body'
747                   | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
748                 )
749              | None -> if l = [] then t' () else C.Appl ((t' ())::l)
750            )
751     | C.CoFix (i,fl) ->
752        let tys =
753         List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
754        in
755         let t' =
756          let fl' =
757           List.map
758            (function (n,ty,bo) ->
759              (n,reduceaux context [] ty, reduceaux (tys@context) [] bo)
760            ) fl
761          in
762          C.CoFix (i, fl')
763        in
764          if l = [] then t' else C.Appl (t'::l)
765  and reduceaux_exp_named_subst context l =
766   List.map (function uri,t -> uri,reduceaux context [] t)
767  (**** Step 2 ****)
768  and try_delta_expansion l term body =
769   let module C = Cic in
770   let module S = CicSubstitution in
771    try
772     let res,constant_args =
773      let rec aux rev_constant_args l =
774       function
775          C.Lambda (name,s,t) as t' ->
776           begin
777            match l with
778               [] -> raise WrongShape
779             | he::tl ->
780                (* when name is Anonimous the substitution should *)
781                (* be superfluous                                 *)
782                aux (he::rev_constant_args) tl (S.subst he t)
783           end
784        | C.LetIn (_,s,t) ->
785           aux rev_constant_args l (S.subst s t)
786        | C.Fix (i,fl) as t ->
787           let tys =
788            List.map (function (name,_,ty,_) ->
789             Some (C.Name name, C.Decl ty)) fl
790           in
791            let (_,recindex,_,body) = List.nth fl i in
792             let recparam =
793              try
794               List.nth l recindex
795              with
796               _ -> raise AlreadySimplified
797             in
798              (match CicReduction.whd context recparam with
799                  C.MutConstruct _
800                | C.Appl ((C.MutConstruct _)::_) ->
801                   let body' =
802                    let counter = ref (List.length fl) in
803                     List.fold_right
804                      (function _ ->
805                        decr counter ; S.subst (C.Fix (!counter,fl))
806                      ) fl body
807                   in
808                    (* Possible optimization: substituting whd *)
809                    (* recparam in l                           *)
810                    reduceaux context l body',
811                     List.rev rev_constant_args
812                | _ -> raise AlreadySimplified
813              )
814        | _ -> raise WrongShape
815      in
816       aux [] l body
817     in
818      (**** Step 3 ****)
819      let term_to_fold, delta_expanded_term_to_fold =
820       match constant_args with
821          [] -> term,body
822        | _ -> C.Appl (term::constant_args), C.Appl (body::constant_args)
823      in
824       let simplified_term_to_fold =
825        reduceaux context [] delta_expanded_term_to_fold
826       in
827        replace (=) [simplified_term_to_fold] [term_to_fold] res
828    with
829       WrongShape ->
830        (* The constant does not unfold to a Fix lambda-abstracted  *)
831        (* w.r.t. zero or more variables. We just perform reduction.*)
832        reduceaux context l body
833     | AlreadySimplified ->
834        (* If we performed delta-reduction, we would find a Fix   *)
835        (* not applied to a constructor. So, we refuse to perform *)
836        (* delta-reduction.                                       *)
837        if l = [] then term else C.Appl (term::l)
838  in
839   reduceaux context []
840 ;;