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