]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/cic_unification/cicMetaSubst.ml
Restrict reimplemented to avoid generating lists of indexes to be restricted
[helm.git] / helm / ocaml / cic_unification / cicMetaSubst.ml
1
2 open Printf
3
4 exception AssertFailure of string
5 exception MetaSubstFailure of string
6
7 let debug_print = prerr_endline
8
9 type substitution = (int * Cic.term) list
10
11 let ppsubst subst =
12   String.concat "\n"
13     (List.map
14       (fun (idx, term) -> Printf.sprintf "?%d := %s" idx (CicPp.ppterm term))
15       subst)
16
17 (**** DELIFT ****)
18 (* the delift function takes in input a metavariable index, an ordered list of
19  * optional terms [t1,...,tn] and a term t, and substitutes every tk = Some
20  * (rel(nk)) with rel(k).  Typically, the list of optional terms is the explicit
21  * substitution that is applied to a metavariable occurrence and the result of
22  * the delift function is a term the implicit variable can be substituted with
23  * to make the term [t] unifiable with the metavariable occurrence.  In general,
24  * the problem is undecidable if we consider equivalence in place of alpha
25  * convertibility. Our implementation, though, is even weaker than alpha
26  * convertibility, since it replace the term [tk] if and only if [tk] is a Rel
27  * (missing all the other cases). Does this matter in practice?
28  * The metavariable index is the index of the metavariable that must not occur
29  * in the term (for occur check).
30  *)
31
32 exception NotInTheList;;
33
34 let position n =
35   let rec aux k =
36    function 
37        [] -> raise NotInTheList
38      | (Some (Cic.Rel m))::_ when m=n -> k
39      | _::tl -> aux (k+1) tl in
40   aux 1
41 ;;
42
43 exception Occur;;
44
45 let rec force_does_not_occur subst to_be_restricted t =
46  let module C = Cic in
47  let more_to_be_restricted = ref [] in
48  let rec aux k = function
49       C.Rel r when List.mem (r - k) to_be_restricted -> raise Occur
50     | C.Rel _
51     | C.Sort _ as t -> t
52     | C.Implicit -> assert false
53     | C.Meta (n, l) ->
54        (* we do not retrieve the term associated to ?n in subst since *)
55        (* in this way we can restrict if something goes wrong         *)
56        let l' =
57          let i = ref 0 in
58          List.map
59            (function t ->
60              incr i ;
61              match t with
62                 None -> None
63               | Some t ->
64                  try
65                    Some (aux k t)
66                  with Occur ->
67                    more_to_be_restricted := (n,!i) :: !more_to_be_restricted;
68                    None)
69            l
70        in
71         C.Meta (n, l')
72     | C.Cast (te,ty) -> C.Cast (aux k te, aux k ty)
73     | C.Prod (name,so,dest) -> C.Prod (name, aux k so, aux (k+1) dest)
74     | C.Lambda (name,so,dest) -> C.Lambda (name, aux k so, aux (k+1) dest)
75     | C.LetIn (name,so,dest) -> C.LetIn (name, aux k so, aux (k+1) dest)
76     | C.Appl l -> C.Appl (List.map (aux k) l)
77     | C.Var (uri,exp_named_subst) ->
78         let exp_named_subst' =
79           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
80         in
81         C.Var (uri, exp_named_subst')
82     | C.Const (uri, exp_named_subst) ->
83         let exp_named_subst' =
84           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
85         in
86         C.Const (uri, exp_named_subst')
87     | C.MutInd (uri,tyno,exp_named_subst) ->
88         let exp_named_subst' =
89           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
90         in
91         C.MutInd (uri, tyno, exp_named_subst')
92     | C.MutConstruct (uri,tyno,consno,exp_named_subst) ->
93         let exp_named_subst' =
94           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
95         in
96         C.MutConstruct (uri, tyno, consno, exp_named_subst')
97     | C.MutCase (uri,tyno,out,te,pl) ->
98         C.MutCase (uri, tyno, aux k out, aux k te, List.map (aux k) pl)
99     | C.Fix (i,fl) ->
100        let len = List.length fl in
101        let k_plus_len = k + len in
102        let fl' =
103          List.map
104           (fun (name,j,ty,bo) -> (name, j, aux k ty, aux k_plus_len bo)) fl
105        in
106        C.Fix (i, fl')
107     | C.CoFix (i,fl) ->
108        let len = List.length fl in
109        let k_plus_len = k + len in
110        let fl' =
111          List.map
112           (fun (name,ty,bo) -> (name, aux k ty, aux k_plus_len bo)) fl
113        in
114        C.CoFix (i, fl')
115  in
116  let res = aux 0 t in
117  (!more_to_be_restricted, res)
118  
119 let rec restrict subst to_be_restricted metasenv =
120   let names_of_context_indexes context indexes =
121     String.concat ", "
122       (List.map
123         (fun i ->
124           try
125            match List.nth context i with
126            | None -> assert false
127            | Some (n, _) -> CicPp.ppname n
128           with
129            Failure _ -> assert false
130         ) indexes)
131   in
132   let force_does_not_occur_in_context to_be_restricted = function
133     | None -> [], None
134     | Some (name, Cic.Decl t) ->
135         let (more_to_be_restricted, t') =
136           force_does_not_occur subst to_be_restricted t
137         in
138         more_to_be_restricted, Some (name, Cic.Decl t')
139     | Some (name, Cic.Def (bo, ty)) ->
140         let (more_to_be_restricted, bo') =
141           force_does_not_occur subst to_be_restricted bo
142         in
143         let more_to_be_restricted, ty' =
144           match ty with
145           | None ->  more_to_be_restricted, None
146           | Some ty ->
147               let more_to_be_restricted', ty' =
148                 force_does_not_occur subst to_be_restricted ty
149               in
150               more_to_be_restricted @ more_to_be_restricted',
151               Some ty'
152         in
153         more_to_be_restricted, Some (name, Cic.Def (bo', ty'))
154   in
155   let rec erase i to_be_restricted n = function
156     | [] -> [], to_be_restricted, []
157     | hd::tl ->
158         let more_to_be_restricted,restricted,tl' =
159          erase (i+1) to_be_restricted n tl
160         in
161         let restrict_me = List.mem i restricted in
162         if restrict_me then
163          more_to_be_restricted, restricted, None:: tl'
164         else
165           (try
166             let more_to_be_restricted', hd' =
167               let delifted_restricted =
168                let rec aux =
169                 function
170                    [] -> []
171                  | j::tl when j > i -> (j - i)::aux tl
172                  | _::tl -> aux tl
173                in
174                 aux restricted
175               in
176                force_does_not_occur_in_context delifted_restricted hd
177             in
178              more_to_be_restricted @ more_to_be_restricted',
179              restricted, hd' :: tl'
180           with Occur ->
181             more_to_be_restricted, (i :: restricted), None :: tl')
182   in
183   let (more_to_be_restricted, metasenv, subst) =
184     List.fold_right
185       (fun (n, context, t) (more, metasenv, subst) ->
186         let to_be_restricted =
187           List.map snd (List.filter (fun (m, _) -> m = n) to_be_restricted)
188         in
189         let (more_to_be_restricted, restricted, context') =
190          (* just an optimization *)
191          if to_be_restricted = [] then
192           [],[],context
193          else
194           erase 1 to_be_restricted n context
195         in
196         try
197           let more_to_be_restricted', t' =
198             force_does_not_occur subst restricted t
199           in
200           let metasenv' = (n, context', t') :: metasenv in
201           (try
202             let s = List.assoc n subst in
203             try
204               let more_to_be_restricted'', s' =
205                 force_does_not_occur subst restricted s
206               in
207               let subst' = (n, s') :: (List.remove_assoc n subst) in
208               let more =
209                 more @ more_to_be_restricted @ more_to_be_restricted' @
210                   more_to_be_restricted''
211               in
212               (more, metasenv', subst')
213             with Occur ->
214               raise (MetaSubstFailure (sprintf
215                 "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since ?%d is already instantiated with %s and at least one of the hypotheses occurs in the substituted term"
216                 n (names_of_context_indexes context to_be_restricted) n
217                 (CicPp.ppterm s)))
218            with Not_found -> (more @ more_to_be_restricted @ more_to_be_restricted', metasenv', subst))
219         with Occur ->
220           raise (MetaSubstFailure (sprintf
221             "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since metavariable's type depends on at least one of them"
222             n (names_of_context_indexes context to_be_restricted))))
223       metasenv ([], [], subst)
224   in
225   match more_to_be_restricted with
226   | [] -> (metasenv, subst)
227   | _ -> restrict subst more_to_be_restricted metasenv
228 ;;
229
230 (*CSC: maybe we should rename delift in abstract, as I did in my dissertation *)
231 let delift n subst context metasenv l t =
232  let module S = CicSubstitution in
233 (* THIS CODE SHOULD NOT BE USEFUL AT ALL
234   let l =
235    let (_, canonical_context, _) = CicUtil.lookup_meta n metasenv in
236    List.map2 (fun ct lt ->
237      match (ct, lt) with
238      | None, _ -> None
239      | Some _, _ -> lt)
240      canonical_context l
241   in
242 *)
243   let to_be_restricted = ref [] in
244   let rec deliftaux k =
245    let module C = Cic in
246     function
247        C.Rel m -> 
248          if m <=k then
249           C.Rel m   (*CSC: che succede se c'e' un Def? Dovrebbe averlo gia' *)
250                     (*CSC: deliftato la regola per il LetIn                 *)
251                     (*CSC: FALSO! La regola per il LetIn non lo fa          *)
252          else
253           (match List.nth context (m-k-1) with
254             Some (_,C.Def (t,_)) ->
255              (*CSC: Hmmm. This bit of reduction is not in the spirit of    *)
256              (*CSC: first order unification. Does it help or does it harm? *)
257              deliftaux k (S.lift m t)
258           | Some (_,C.Decl t) ->
259              (*CSC: The following check seems to be wrong!             *)
260              (*CSC: B:Set |- ?2 : Set                                  *)
261              (*CSC: A:Set ; x:?2[A/B] |- ?1[x/A] =?= x                 *)
262              (*CSC: Why should I restrict ?2 over B? The instantiation *)
263              (*CSC: ?1 := A is perfectly reasonable and well-typed.    *)
264              (*CSC: Thus I comment out the following two lines that    *)
265              (*CSC: are the incriminated ones.                         *)
266              (*(* It may augment to_be_restricted *)
267                ignore (deliftaux k (S.lift m t)) ;*)
268              (*CSC: end of bug commented out                           *)
269              C.Rel ((position (m-k) l) + k)
270           | None -> raise (MetaSubstFailure "RelToHiddenHypothesis"))
271      | C.Var (uri,exp_named_subst) ->
272         let exp_named_subst' =
273          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
274         in
275          C.Var (uri,exp_named_subst')
276      | C.Meta (i, l1) as t -> 
277         if i = n then
278           raise (MetaSubstFailure (sprintf
279             "Cannot unify the metavariable ?%d with a term that has as subterm %s in which the same metavariable occurs (occur check)"
280             i (CicPp.ppterm t)))
281         else
282          (* I do not consider the term associated to ?i in subst since *)
283          (* in this way I can restrict if something goes wrong.        *)
284           let rec deliftl j =
285            function
286               [] -> []
287             | None::tl -> None::(deliftl (j+1) tl)
288             | (Some t)::tl ->
289                let l1' = (deliftl (j+1) tl) in
290                 try
291                  Some (deliftaux k t)::l1'
292                 with
293                    NotInTheList
294                  | MetaSubstFailure _ ->
295                     to_be_restricted := (i,j)::!to_be_restricted ; None::l1'
296           in
297            let l' = deliftl 1 l1 in
298             C.Meta(i,l')
299      | C.Sort _ as t -> t
300      | C.Implicit as t -> t
301      | C.Cast (te,ty) -> C.Cast (deliftaux k te, deliftaux k ty)
302      | C.Prod (n,s,t) -> C.Prod (n, deliftaux k s, deliftaux (k+1) t)
303      | C.Lambda (n,s,t) -> C.Lambda (n, deliftaux k s, deliftaux (k+1) t)
304      | C.LetIn (n,s,t) -> C.LetIn (n, deliftaux k s, deliftaux (k+1) t)
305      | C.Appl l -> C.Appl (List.map (deliftaux k) l)
306      | C.Const (uri,exp_named_subst) ->
307         let exp_named_subst' =
308          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
309         in
310          C.Const (uri,exp_named_subst')
311      | C.MutInd (uri,typeno,exp_named_subst) ->
312         let exp_named_subst' =
313          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
314         in
315          C.MutInd (uri,typeno,exp_named_subst')
316      | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
317         let exp_named_subst' =
318          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
319         in
320          C.MutConstruct (uri,typeno,consno,exp_named_subst')
321      | C.MutCase (sp,i,outty,t,pl) ->
322         C.MutCase (sp, i, deliftaux k outty, deliftaux k t,
323          List.map (deliftaux k) pl)
324      | C.Fix (i, fl) ->
325         let len = List.length fl in
326         let liftedfl =
327          List.map
328           (fun (name, i, ty, bo) ->
329            (name, i, deliftaux k ty, deliftaux (k+len) bo))
330            fl
331         in
332          C.Fix (i, liftedfl)
333      | C.CoFix (i, fl) ->
334         let len = List.length fl in
335         let liftedfl =
336          List.map
337           (fun (name, ty, bo) -> (name, deliftaux k ty, deliftaux (k+len) bo))
338            fl
339         in
340          C.CoFix (i, liftedfl)
341   in
342    let res =
343     try
344      deliftaux 0 t
345     with
346      NotInTheList ->
347       (* This is the case where we fail even first order unification. *)
348       (* The reason is that our delift function is weaker than first  *)
349       (* order (in the sense of alpha-conversion). See comment above  *)
350       (* related to the delift function.                              *)
351 debug_print "!!!!!!!!!!! First Order UnificationFailure, but maybe it could have been successful even in a first order setting (no conversion, only alpha convertibility)! Please, implement a better delift function !!!!!!!!!!!!!!!!" ;
352       raise (MetaSubstFailure (sprintf
353         "Error trying to abstract %s over [%s]: the algorithm only tried to abstract over bound variables"
354         (CicPp.ppterm t)
355         (String.concat "; "
356           (List.map
357             (function Some t -> CicPp.ppterm t | None -> "_")
358             l))))
359    in
360    let (metasenv, subst) = restrict subst !to_be_restricted metasenv in
361     res, metasenv, subst
362 ;;
363
364 (**** END OF DELIFT ****)
365
366 let apply_subst_gen ~appl_fun subst term =
367  let rec um_aux =
368   let module C = Cic in
369   let module S = CicSubstitution in 
370    function
371       C.Rel _ as t -> t
372     | C.Var _  as t -> t
373     | C.Meta (i, l) -> 
374         (try
375           let t = List.assoc i subst in
376           um_aux (S.lift_meta l t)
377         with Not_found -> (* not constrained variable, i.e. free in subst*)
378           let l' =
379             List.map (function None -> None | Some t -> Some (um_aux t)) l
380           in
381            C.Meta (i,l'))
382     | C.Sort _ as t -> t
383     | C.Implicit -> assert false
384     | C.Cast (te,ty) -> C.Cast (um_aux te, um_aux ty)
385     | C.Prod (n,s,t) -> C.Prod (n, um_aux s, um_aux t)
386     | C.Lambda (n,s,t) -> C.Lambda (n, um_aux s, um_aux t)
387     | C.LetIn (n,s,t) -> C.LetIn (n, um_aux s, um_aux t)
388     | C.Appl (hd :: tl) -> appl_fun um_aux hd tl
389     | C.Appl _ -> assert false
390     | C.Const (uri,exp_named_subst) ->
391        let exp_named_subst' =
392          List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
393        in
394        C.Const (uri, exp_named_subst')
395     | C.MutInd (uri,typeno,exp_named_subst) ->
396        let exp_named_subst' =
397          List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
398        in
399        C.MutInd (uri,typeno,exp_named_subst')
400     | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
401        let exp_named_subst' =
402          List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
403        in
404        C.MutConstruct (uri,typeno,consno,exp_named_subst')
405     | C.MutCase (sp,i,outty,t,pl) ->
406        let pl' = List.map um_aux pl in
407        C.MutCase (sp, i, um_aux outty, um_aux t, pl')
408     | C.Fix (i, fl) ->
409        let fl' =
410          List.map (fun (name, i, ty, bo) -> (name, i, um_aux ty, um_aux bo)) fl
411        in
412        C.Fix (i, fl')
413     | C.CoFix (i, fl) ->
414        let fl' =
415          List.map (fun (name, ty, bo) -> (name, um_aux ty, um_aux bo)) fl
416        in
417        C.CoFix (i, fl')
418  in
419  um_aux term
420
421 let apply_subst =
422   let appl_fun um_aux he tl =
423     let tl' = List.map um_aux tl in
424       begin
425        match um_aux he with
426           Cic.Appl l -> Cic.Appl (l@tl')
427         | he' -> Cic.Appl (he'::tl')
428       end
429   in
430   apply_subst_gen ~appl_fun
431
432 let ppterm subst term = CicPp.ppterm (apply_subst subst term)
433
434 (* apply_subst_reducing subst (Some (mtr,reductions_no)) t              *)
435 (* performs as (apply_subst subst t) until it finds an application of   *)
436 (* (META [meta_to_reduce]) that, once unwinding is performed, creates   *)
437 (* a new beta-redex; in this case up to [reductions_no] consecutive     *)
438 (* beta-reductions are performed.                                       *)
439 (* Hint: this function is usually called when [reductions_no]           *)
440 (*  eta-expansions have been performed and the head of the new          *)
441 (*  application has been unified with (META [meta_to_reduce]):          *)
442 (*  during the unwinding the eta-expansions are undone.                 *)
443
444 let apply_subst_reducing meta_to_reduce =
445   let appl_fun um_aux he tl =
446     let tl' = List.map um_aux tl in
447     let t' =
448      match um_aux he with
449         Cic.Appl l -> Cic.Appl (l@tl')
450       | he' -> Cic.Appl (he'::tl')
451     in
452      begin
453       match meta_to_reduce, he with
454          Some (mtr,reductions_no), Cic.Meta (m,_) when m = mtr ->
455           let rec beta_reduce =
456            function
457               (n,(Cic.Appl (Cic.Lambda (_,_,t)::he'::tl'))) when n > 0 ->
458                 let he'' = CicSubstitution.subst he' t in
459                  if tl' = [] then
460                   he''
461                  else
462                   beta_reduce (n-1,Cic.Appl(he''::tl'))
463             | (_,t) -> t
464           in
465            beta_reduce (reductions_no,t')
466        | _,_ -> t'
467      end
468   in
469   apply_subst_gen ~appl_fun
470
471 let rec apply_subst_context subst context =
472   List.fold_right
473     (fun item context ->
474       match item with
475       | Some (n, Cic.Decl t) ->
476           let t' = apply_subst subst t in
477           Some (n, Cic.Decl t') :: context
478       | Some (n, Cic.Def (t, ty)) ->
479           let ty' =
480             match ty with
481             | None -> None
482             | Some ty -> Some (apply_subst subst ty)
483           in
484           let t' = apply_subst subst t in
485           Some (n, Cic.Def (t', ty')) :: context
486       | None -> None :: context)
487     context []
488
489 let apply_subst_metasenv subst metasenv =
490   List.map
491     (fun (n, context, ty) ->
492       (n, apply_subst_context subst context, apply_subst subst ty))
493     (List.filter
494       (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
495       metasenv)
496
497 let ppterm subst term = CicPp.ppterm (apply_subst subst term)
498
499 let ppterm_in_context subst term name_context =
500  CicPp.pp (apply_subst subst term) name_context
501
502 let ppcontext' ?(sep = "\n") subst context =
503  let separate s = if s = "" then "" else s ^ sep in
504   List.fold_right 
505    (fun context_entry (i,name_context) ->
506      match context_entry with
507         Some (n,Cic.Decl t) ->
508          sprintf "%s%s : %s" (separate i) (CicPp.ppname n)
509           (ppterm_in_context subst t name_context), (Some n)::name_context
510       | Some (n,Cic.Def (bo,ty)) ->
511          sprintf "%s%s : %s := %s" (separate i) (CicPp.ppname n)
512           (match ty with
513               None -> "_"
514             | Some ty -> ppterm_in_context subst ty name_context)
515           (ppterm_in_context subst bo name_context), (Some n)::name_context
516        | None ->
517           sprintf "%s_ :? _" (separate i), None::name_context
518     ) context ("",[])
519
520 let ppcontext ?sep subst context = fst (ppcontext' ?sep subst context)
521
522 let ppmetasenv ?(sep = "\n") metasenv subst =
523   String.concat sep
524     (List.map
525       (fun (i, c, t) ->
526         let context,name_context = ppcontext' ~sep:"; " subst c in
527          sprintf "%s |- ?%d: %s" context i
528           (ppterm_in_context subst t name_context))
529       (List.filter
530         (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
531         metasenv))
532
533 (* UNWIND THE MGU INSIDE THE MGU *)
534 (*
535 let unwind_subst metasenv subst =
536   List.fold_left
537    (fun (unwinded,metasenv) (i,_) ->
538      let (_,canonical_context,_) = CicUtil.lookup_meta i metasenv in
539      let identity_relocation_list =
540       CicMkImplicit.identity_relocation_list_for_metavariable canonical_context
541      in
542       let (_,metasenv',subst') =
543        unwind metasenv subst unwinded (Cic.Meta (i,identity_relocation_list))
544       in
545        subst',metasenv'
546    ) ([],metasenv) subst
547 *)
548
549 (* From now on we recreate a kernel abstraction where substitutions are part of
550  * the calculus *)
551
552 let lift subst n term =
553   let term = apply_subst subst term in
554   try
555     CicSubstitution.lift n term
556   with e ->
557     raise (MetaSubstFailure ("Lift failure: " ^ Printexc.to_string e))
558
559 let subst subst t1 t2 =
560   let t1 = apply_subst subst t1 in
561   let t2 = apply_subst subst t2 in
562   try
563     CicSubstitution.subst t1 t2
564   with e ->
565     raise (MetaSubstFailure ("Subst failure: " ^ Printexc.to_string e))
566
567 let whd subst context term =
568   let term = apply_subst subst term in
569   let context = apply_subst_context subst context in
570   try
571     CicReduction.whd context term
572   with e ->
573     raise (MetaSubstFailure ("Weak head reduction failure: " ^
574       Printexc.to_string e))
575
576 let are_convertible subst context t1 t2 =
577   let context = apply_subst_context subst context in
578   let t1 = apply_subst subst t1 in
579   let t2 = apply_subst subst t2 in
580   CicReduction.are_convertible context t1 t2
581
582 let tempi_type_of_aux_subst = ref 0.0;;
583 let tempi_type_of_aux = ref 0.0;;
584
585 let type_of_aux' metasenv subst context term =
586 let time1 = Unix.gettimeofday () in
587   let term = apply_subst subst term in
588   let context = apply_subst_context subst context in
589   let metasenv =
590     List.map
591       (fun (i, c, t) -> (i, apply_subst_context subst c, apply_subst subst t))
592       (List.filter
593         (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
594         metasenv)
595   in
596 let time2 = Unix.gettimeofday () in
597 let res =
598   try
599     CicTypeChecker.type_of_aux' metasenv context term
600   with CicTypeChecker.TypeCheckerFailure msg ->
601     raise (MetaSubstFailure ("Type checker failure: " ^ msg))
602 in
603 let time3 = Unix.gettimeofday () in
604  tempi_type_of_aux_subst := !tempi_type_of_aux_subst +. time3 -. time1 ; 
605  tempi_type_of_aux := !tempi_type_of_aux +. time2 -. time1 ; 
606  res