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