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