]> matita.cs.unibo.it Git - fireball-separation.git/blob - ocaml/andrea.ml
Added check with purification to andrea.ml
[fireball-separation.git] / ocaml / andrea.ml
1 let (++) f g x = f (g x);;\r
2 let id x = x;;\r
3 let rec fold_nat f x n = if n = 0 then x else f (fold_nat f x (n-1)) n ;;\r
4 \r
5 let print_hline = Console.print_hline;;\r
6 \r
7 open Pure\r
8 \r
9 type var = int;;\r
10 type t =\r
11  | V of var\r
12  | A of t * t\r
13  | L of t\r
14  | B (* bottom *)\r
15 ;;\r
16 \r
17 let eta_eq =\r
18  let rec aux l1 l2 t1 t2 = match t1, t2 with\r
19   | L t1, L t2 -> aux l1 l2 t1 t2\r
20   | L t1, t2 -> aux l1 (l2+1) t1 t2\r
21   | t1, L t2 -> aux (l1+1) l2 t1 t2\r
22   | V a, V b -> a + l1 = b + l2\r
23   | A(t1,t2), A(u1,u2) -> aux l1 l2 t1 u1 && aux l1 l2 t2 u2\r
24   | _, _ -> false\r
25  in aux 0 0\r
26 ;;\r
27 \r
28 (* does NOT lift t *)\r
29 let mk_lams = fold_nat (fun x _ -> L x) ;;\r
30 \r
31 let string_of_t =\r
32   let string_of_bvar =\r
33    let bound_vars = ["x"; "y"; "z"; "w"; "q"] in\r
34    let bvarsno = List.length bound_vars in\r
35    fun nn -> if nn < bvarsno then List.nth bound_vars nn else "x" ^ (string_of_int (nn - bvarsno + 1)) in\r
36   let rec string_of_term_w_pars level = function\r
37     | V v -> if v >= level then "`" ^ string_of_int (v-level) else\r
38        string_of_bvar (level - v-1)\r
39     | A _\r
40     | L _ as t -> "(" ^ string_of_term_no_pars level t ^ ")"\r
41     | B -> "BOT"\r
42   and string_of_term_no_pars_app level = function\r
43     | A(t1,t2) -> string_of_term_no_pars_app level t1 ^ " " ^ string_of_term_w_pars level t2\r
44     | _ as t -> string_of_term_w_pars level t\r
45   and string_of_term_no_pars level = function\r
46     | L t -> "λ" ^ string_of_bvar level ^ ". " ^ string_of_term_no_pars (level+1) t\r
47     | _ as t -> string_of_term_no_pars_app level t\r
48   in string_of_term_no_pars 0\r
49 ;;\r
50 \r
51 type problem = {\r
52    orig_freshno: int\r
53  ; freshno : int\r
54  ; div : t\r
55  ; conv : t\r
56  ; sigma : (var * t) list (* substitutions *)\r
57  ; stepped : var list\r
58 }\r
59 \r
60 let string_of_problem p =\r
61  let lines = [\r
62   "[stepped] " ^ String.concat " " (List.map string_of_int p.stepped);\r
63   "[DV] " ^ string_of_t p.div;\r
64   "[CV] " ^ string_of_t p.conv;\r
65  ] in\r
66  String.concat "\n" lines\r
67 ;;\r
68 \r
69 exception Done of (var * t) list (* substitution *);;\r
70 exception Fail of int * string;;\r
71 \r
72 let problem_fail p reason =\r
73  print_endline "!!!!!!!!!!!!!!! FAIL !!!!!!!!!!!!!!!";\r
74  print_endline (string_of_problem p);\r
75  raise (Fail (-1, reason))\r
76 ;;\r
77 \r
78 let freshvar ({freshno} as p) =\r
79  {p with freshno=freshno+1}, freshno+1\r
80 ;;\r
81 \r
82 let rec is_inert =\r
83  function\r
84  | A(t,_) -> is_inert t\r
85  | V _ -> true\r
86  | L _ | B -> false\r
87 ;;\r
88 \r
89 let is_var = function V _ -> true | _ -> false;;\r
90 let is_lambda = function L _ -> true | _ -> false;;\r
91 \r
92 let rec no_leading_lambdas = function\r
93  | L t -> 1 + no_leading_lambdas t\r
94  | _ -> 0\r
95 ;;\r
96 \r
97 let rec get_inert = function\r
98  | V n -> (n,0)\r
99  | A(t, _) -> let hd,args = get_inert t in hd,args+1\r
100  | _ -> assert false\r
101 ;;\r
102 \r
103 let rec subst level delift sub =\r
104  function\r
105  | V v -> if v = level + fst sub then lift level (snd sub) else V (if delift && v > level then v-1 else v)\r
106  | L t -> L (subst (level + 1) delift sub t)\r
107  | A (t1,t2) ->\r
108   let t1 = subst level delift sub t1 in\r
109   let t2 = subst level delift sub t2 in\r
110   mk_app t1 t2\r
111  | B -> B\r
112 and mk_app t1 t2 = match t1 with\r
113  | B | _ when t2 = B -> B\r
114  | L t1 -> subst 0 true (0, t2) t1\r
115  | t1 -> A (t1, t2)\r
116 and lift n =\r
117  let rec aux lev =\r
118   function\r
119   | V m -> V (if m >= lev then m + n else m)\r
120   | L t -> L (aux (lev+1) t)\r
121   | A (t1, t2) -> A (aux lev t1, aux lev t2)\r
122   | B -> B\r
123  in aux 0\r
124 ;;\r
125 let subst = subst 0 false;;\r
126 \r
127 let subst_in_problem (sub: var * t) (p: problem) =\r
128 print_endline ("-- SUBST " ^ string_of_t (V (fst sub)) ^ " |-> " ^ string_of_t (snd sub));\r
129  {p with\r
130   div=subst sub p.div;\r
131   conv=subst sub p.conv;\r
132   stepped=(fst sub)::p.stepped;\r
133   sigma=sub::p.sigma}\r
134 ;;\r
135 \r
136 let get_subterm_with_head_and_args hd_var n_args =\r
137  let rec aux lev = function\r
138  | V _ | B -> None\r
139  | L t -> aux (lev+1) t\r
140  | A(t1,t2) as t ->\r
141    let hd_var', n_args' = get_inert t1 in\r
142    if hd_var' = hd_var + lev && n_args <= 1 + n_args'\r
143     then Some (lift ~-lev t)\r
144     else match aux lev t2 with\r
145     | None -> aux lev t1\r
146     | Some _ as res -> res\r
147  in aux 0\r
148 ;;\r
149 \r
150 let rec purify = function\r
151  | L t -> Pure.L (purify t)\r
152  | A (t1,t2) -> Pure.A (purify t1, purify t2)\r
153  | V n -> Pure.V n\r
154  | B -> Pure.B\r
155 ;;\r
156 \r
157 let check p sigma =\r
158  let div = purify p.div in\r
159  let conv = purify p.conv in\r
160  let sigma = List.map (fun (v,t) -> v, purify t) sigma in\r
161  let freshno = List.fold_right (fun (x,_) -> max x) sigma 0 in\r
162  let env = Pure.env_of_sigma freshno sigma in\r
163  assert (Pure.diverged (Pure.mwhd (env,div,[])));\r
164  assert (not (Pure.diverged (Pure.mwhd (env,conv,[]))));\r
165  ()\r
166 ;;\r
167 \r
168 let sanity p =\r
169  print_endline (string_of_problem p); (* non cancellare *)\r
170  if p.conv = B then problem_fail p "p.conv diverged";\r
171  if p.div = B then raise (Done p.sigma);\r
172  if not (is_inert p.div) then problem_fail p "p.div converged"\r
173 ;;\r
174 \r
175 let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);;\r
176 \r
177 (* eat the arguments of the divergent and explode.\r
178  It does NOT perform any check, may fail if done unsafely *)\r
179 let eat p =\r
180 print_cmd "EAT" "";\r
181  let var, n = get_inert p.div in\r
182  let subst = var, mk_lams B n in\r
183  let p = subst_in_problem subst p in\r
184  sanity p; p\r
185 ;;\r
186 \r
187 (* step on the head of div, on the k-th argument, with n fresh vars *)\r
188 let step k n p =\r
189  let var, _ = get_inert p.div in\r
190 print_cmd "STEP" ("on " ^ string_of_t (V var) ^ " (of:" ^ string_of_int n ^ ")");\r
191  let p, t = (* apply fresh vars *)\r
192   fold_nat (fun (p, t) _ ->\r
193     let p, v = freshvar p in\r
194     p, A(t, V (v + k + 1))\r
195   ) (p, V 0) n in\r
196  let t = (* apply unused bound variables V_{k-1}..V_1 *)\r
197   fold_nat (fun t m -> A(t, V (k-m+1))) t k in\r
198  let t = mk_lams t (k+1) in (* make leading lambdas *)\r
199  let subst = var, t in\r
200  let p = subst_in_problem subst p in\r
201  sanity p; p\r
202 ;;\r
203 \r
204 let parse strs =\r
205   let rec aux level = function\r
206   | Parser_andrea.Lam t -> L (aux (level + 1) t)\r
207   | Parser_andrea.App (t1, t2) ->\r
208    if level = 0 then mk_app (aux level t1) (aux level t2)\r
209     else A(aux level t1, aux level t2)\r
210   | Parser_andrea.Var v -> V v in\r
211   let (tms, free) = Parser_andrea.parse_many strs in\r
212   (List.map (aux 0) tms, free)\r
213 ;;\r
214 \r
215 let problem_of div conv =\r
216  print_hline ();\r
217  let [@warning "-8"] [div; conv], var_names = parse ([div; conv]) in\r
218  let varno = List.length var_names in\r
219  let p = {orig_freshno=varno; freshno=1+varno; div; conv; sigma=[]; stepped=[]} in\r
220  (* initial sanity check *)\r
221  sanity p; p\r
222 ;;\r
223 \r
224 let exec div conv cmds =\r
225  let p = problem_of div conv in\r
226  try\r
227   problem_fail (List.fold_left (|>) p cmds) "Problem not completed"\r
228  with\r
229  | Done _ -> ()\r
230 ;;\r
231 \r
232 (* drops the arguments of t after the n-th *)\r
233 let inert_cut_at n t =\r
234  let rec aux t =\r
235   match t with\r
236   | V _ as t -> 0, t\r
237   | A(t1,_) as t ->\r
238     let k', t' = aux t1 in\r
239      if k' = n then n, t'\r
240       else k'+1, t\r
241   | _ -> assert false\r
242  in snd (aux t)\r
243 ;;\r
244 \r
245 let find_eta_difference p t n_args =\r
246  let t = inert_cut_at n_args t in\r
247  let rec aux t u k = match t, u with\r
248  | V _, V _ -> assert false (* div subterm of conv *)\r
249  | A(t1,t2), A(u1,u2) ->\r
250     if not (eta_eq t2 u2) then (print_endline((string_of_t t2) ^ " <> " ^ (string_of_t u2)); k)\r
251     else aux t1 u1 (k-1)\r
252  | _, _ -> assert false\r
253  in aux p.div t n_args\r
254 ;;\r
255 \r
256 let compute_max_lambdas_at hd_var j =\r
257  let rec aux hd = function\r
258  | A(t1,t2) ->\r
259     (if get_inert t1 = (hd, j)\r
260       then max ( (*FIXME*)\r
261        if is_inert t2 && let hd', j' = get_inert t2 in hd' = hd\r
262         then let hd', j' = get_inert t2 in j - j'\r
263         else no_leading_lambdas t2)\r
264       else id) (max (aux hd t1) (aux hd t2))\r
265  | L t -> aux (hd+1) t\r
266  | V _ -> 0\r
267  | _ -> assert false\r
268  in aux hd_var\r
269 ;;\r
270 \r
271 let rec auto p =\r
272  let hd_var, n_args = get_inert p.div in\r
273  match get_subterm_with_head_and_args hd_var n_args p.conv with\r
274  | None ->\r
275     (try problem_fail (eat p) "Auto did not complete the problem"  with Done sigma -> sigma)\r
276  | Some t ->\r
277   let j = find_eta_difference p t n_args - 1 in\r
278   let k = 1 + max\r
279    (compute_max_lambdas_at hd_var j p.div)\r
280     (compute_max_lambdas_at hd_var j p.conv) in\r
281   let p = step j k p in\r
282   auto p\r
283 ;;\r
284 \r
285 let interactive div conv cmds =\r
286  let p = problem_of div conv in\r
287  try (\r
288  let p = List.fold_left (|>) p cmds in\r
289  let rec f p cmds =\r
290   let nth spl n = int_of_string (List.nth spl n) in\r
291   let read_cmd () =\r
292    let s = read_line () in\r
293    let spl = Str.split (Str.regexp " +") s in\r
294    s, let uno = List.hd spl in\r
295     try if uno = "eat" then eat\r
296     else if uno = "step" then step (nth spl 1) (nth spl 2)\r
297     else failwith "Wrong input."\r
298     with Failure s -> print_endline s; (fun x -> x) in\r
299   let str, cmd = read_cmd () in\r
300   let cmds = (" " ^ str ^ ";")::cmds in\r
301   try\r
302    let p = cmd p in f p cmds\r
303   with\r
304   | Done _ -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds)\r
305  in f p []\r
306  ) with Done _ -> ()\r
307 ;;\r
308 \r
309 let rec conv_join = function\r
310  | [] -> "@"\r
311  | x::xs -> conv_join xs ^ " ("^ x ^")"\r
312 ;;\r
313 \r
314 let auto' a b =\r
315  let p = problem_of a (conv_join b) in\r
316  let sigma = auto p in\r
317  check p sigma\r
318 ;;\r
319 \r
320 (* Example usage of exec, interactive:\r
321 \r
322 exec\r
323  "x x"\r
324  (conv_join["x y"; "y y"; "y x"])\r
325  [ step 0 1; eat ]\r
326 ;;\r
327 \r
328 interactive "x y"\r
329  "@ (x x) (y x) (y z)" [step 0 1; step 0 2; eat]\r
330 ;;\r
331 \r
332 *)\r
333 \r
334 auto' "x x" ["x y"; "y y"; "y x"] ;;\r
335 auto' "x y" ["x (_. x)"; "y z"; "y x"] ;;\r
336 auto' "a (x. x b) (x. x c)" ["a (x. b b) @"; "a @ c"; "a (x. x x) a"; "a (a a a) (a c c)"] ;;\r
337 \r
338 auto' "x (y. x y y)" ["x (y. x y x)"] ;;\r
339 \r
340 auto' "x a a a a" [\r
341  "x b a a a";\r
342  "x a b a a";\r
343  "x a a b a";\r
344  "x a a a b";\r
345 ] ;;\r
346 \r
347 (* Controesempio ad usare un conto dei lambda che non considere le permutazioni *)\r
348 auto' "x a a a a (x (x. x x) @ @ (_._.x. x x) x) b b b" [\r
349  "x a a a a (_. a) b b b";\r
350  "x a a a a (_. _. _. _. x. y. x y)";\r
351 ] ;;\r
352 \r
353 \r
354 print_hline();\r
355 print_endline "ALL DONE. "\r