]> matita.cs.unibo.it Git - fireball-separation.git/blob - ocaml/andrea.ml
get_subterm_with_head_and_args goes under lambdas
[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 lev = function\r
139  | V _ | B | P -> None\r
140  | L t -> aux (lev+1) t\r
141  | A(t1,t2) as t ->\r
142    if head_of_inert t1 = hd_var + lev && n_args <= 1 + args_no t1 (* why `1+' ?*)\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 simple_explode p =\r
151  match p.div with\r
152  | V var ->\r
153   let subst = var, B in\r
154   sanity (subst_in_problem subst p)\r
155  | _ -> p *)\r
156 \r
157 let sanity p =\r
158  print_endline (string_of_problem p); (* non cancellare *)\r
159  if p.div = B then raise (Done p.sigma);\r
160  if not (is_inert p.div) then problem_fail p "p.div converged";\r
161  if p.conv = B then problem_fail p "p.conv diverged";\r
162  (* let p = if is_var p.div then simple_explode p else p in *)\r
163  p\r
164 ;;\r
165 \r
166 let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);;\r
167 \r
168 (* eat the arguments of the divergent and explode.\r
169  It does NOT perform any check, may fail if done unsafely *)\r
170 let eat p =\r
171 print_cmd "EAT" "";\r
172  let var = head_of_inert p.div in\r
173  let n = args_no p.div in\r
174  let rec aux m t =\r
175   if m = 0\r
176    then lift n t\r
177    else L (aux (m-1) t) in\r
178  let subst = var, aux n B in\r
179  sanity (subst_in_problem subst p)\r
180 ;;\r
181 \r
182 (* step on the head of div, on the k-th argument, with n fresh vars *)\r
183 let step k n p =\r
184  let var = head_of_inert p.div in\r
185  print_cmd "STEP" ("on " ^ string_of_t p (V var) ^ " (of:" ^ string_of_int n ^ ")");\r
186  let rec aux' p m t =\r
187   if m < 0\r
188    then p, t\r
189     else\r
190      let p, v = freshvar p in\r
191      let p, t = aux' p (m-1) t in\r
192       p, A(t, V (v + k + 1)) in\r
193  let p, t = aux' p n (V 0) in\r
194  let rec aux' m t = if m < 0 then t else A(aux' (m-1) t, V (k-m)) in\r
195  let rec aux m t =\r
196   if m < 0\r
197    then aux' (k-1) t\r
198    else L (aux (m-1) t) in\r
199  let t = aux k t in\r
200  let subst = var, t in\r
201  sanity (subst_in_problem subst p)\r
202 ;;\r
203 \r
204 let parse strs =\r
205   let rec aux level = function\r
206   | Parser.Lam t -> L (aux (level + 1) t)\r
207   | Parser.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.Var v -> V v\r
211   in let (tms, free) = Parser.parse_many strs\r
212   in (List.map (aux 0) tms, free)\r
213 ;;\r
214 \r
215 let problem_of div conv =\r
216  print_hline ();\r
217  let all_tms, var_names = parse ([div; conv]) in\r
218  let div, conv = List.hd all_tms, List.hd (List.tl all_tms) in\r
219  let varno = List.length var_names in\r
220  let p = {orig_freshno=varno; freshno=1+varno; div; conv; sigma=[]; stepped=[]} in\r
221  (* activate bombs *)\r
222  let p = try\r
223   let subst = Util.index_of "BOMB" var_names, L B in\r
224    subst_in_problem subst p\r
225   with Not_found -> p in\r
226  (* activate pacmans *)\r
227  let p = try\r
228   let subst = Util.index_of "PACMAN" var_names, P in\r
229    let p = subst_in_problem subst p in\r
230    (print_endline ("after subst in problem " ^ string_of_problem p); p)\r
231   with Not_found -> p in\r
232  (* initial sanity check *)\r
233  sanity p\r
234 ;;\r
235 \r
236 let exec div conv cmds =\r
237  let p = problem_of div conv in\r
238  try\r
239   problem_fail (List.fold_left (|>) p cmds) "Problem not completed"\r
240  with\r
241  | Done _ -> ()\r
242 ;;\r
243 \r
244 let inert_cut_at n t =\r
245  let rec aux t =\r
246   match t with\r
247   | V _ as t -> 0, t\r
248   | A(t1,_) as t ->\r
249     let k', t' = aux t1 in\r
250      if k' = n then n, t'\r
251       else k'+1, t\r
252   | _ -> assert false\r
253  in snd (aux t)\r
254 ;;\r
255 \r
256 let find_eta_difference p t n_args =\r
257  let t = inert_cut_at n_args t in\r
258  let rec aux t u k = match t, u with\r
259  | V _, V _ -> assert false (* div subterm of conv *)\r
260  | A(t1,t2), A(u1,u2) ->\r
261     if not (eta_eq t2 u2) then (print_endline((string_of_t p t2) ^ " <> " ^ (string_of_t p u2)); k)\r
262     else aux t1 u1 (k-1)\r
263  | _, _ -> assert false\r
264  in aux p.div t n_args\r
265 ;;\r
266 \r
267 let rec no_leading_lambdas = function\r
268  | L t -> 1 + no_leading_lambdas t\r
269  | _ -> 0\r
270 ;;\r
271 \r
272 let compute_max_lambdas_at hd_var j =\r
273  let rec aux hd = function\r
274  | A(t1,t2) ->\r
275     (if head_of_inert t1 = hd && args_no t1 = j\r
276       then max (\r
277        if is_inert t2 && head_of_inert t2 = hd\r
278         then j - args_no t2\r
279         else no_leading_lambdas t2)\r
280       else id) (max (aux hd t1) (aux hd t2))\r
281  | L t -> aux (hd+1) t\r
282  | V _ -> 0\r
283  | _ -> assert false\r
284  in aux hd_var\r
285 ;;\r
286 \r
287 let rec auto p =\r
288  let hd_var = head_of_inert p.div in\r
289  let n_args = args_no p.div in\r
290  match get_subterm_with_head_and_args hd_var n_args p.conv with\r
291  | None ->\r
292     (try problem_fail (eat p) "Auto did not complete the problem"  with Done _ -> ())\r
293  | Some t ->\r
294   let j = find_eta_difference p t n_args - 1 in\r
295   let k = max\r
296    (compute_max_lambdas_at hd_var j p.div)\r
297     (compute_max_lambdas_at hd_var j p.conv) in\r
298   let p = step j k p in\r
299   auto p\r
300 ;;\r
301 \r
302 let interactive div conv cmds =\r
303  let p = problem_of div conv in\r
304  try (\r
305  let p = List.fold_left (|>) p cmds in\r
306  let rec f p cmds =\r
307   let nth spl n = int_of_string (List.nth spl n) in\r
308   let read_cmd () =\r
309    let s = read_line () in\r
310    let spl = Str.split (Str.regexp " +") s in\r
311    s, let uno = List.hd spl in\r
312     try if uno = "eat" then eat\r
313     else if uno = "step" then step (nth spl 1) (nth spl 2)\r
314     else failwith "Wrong input."\r
315     with Failure s -> print_endline s; (fun x -> x) in\r
316   let str, cmd = read_cmd () in\r
317   let cmds = (" " ^ str ^ ";")::cmds in\r
318   try\r
319    let p = cmd p in f p cmds\r
320   with\r
321   | Done _ -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds)\r
322  in f p []\r
323  ) with Done _ -> ()\r
324 ;;\r
325 \r
326 let rec conv_join = function\r
327  | [] -> "@"\r
328  | x::xs -> conv_join xs ^ " ("^ x ^")"\r
329 ;;\r
330 \r
331 let auto' a b = auto (problem_of a (conv_join b));;\r
332 \r
333 (* Example usage of exec, interactive:\r
334 \r
335 exec\r
336  "x x"\r
337  (conv_join["x y"; "y y"; "y x"])\r
338  [ step 0 0; eat ]\r
339 ;;\r
340 \r
341 interactive "x y"\r
342  "@ (x x) (y x) (y z)" [step 0 0; step 0 1; eat]\r
343 ;;\r
344 \r
345 *)\r
346 \r
347 auto' "x x" ["x y"; "y y"; "y x"] ;;\r
348 auto' "x y" ["x (_. x)"; "y z"; "y x"] ;;\r
349 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
350 \r
351 auto' "x (y. x y y)" ["x (y. x y x)"] ;;\r
352 \r
353 auto' "x a a a a" [\r
354  "x b a a a";\r
355  "x a b a a";\r
356  "x a a b a";\r
357  "x a a a b";\r
358 ] ;;\r
359 \r
360 (* Controesempio ad usare un conto dei lambda che non considere le permutazioni *)\r
361 auto' "x a a a a (x (x. x x) @ @ (_._.x. x x) x) b b b" [\r
362  "x a a a a (_. a) b b b";\r
363  "x a a a a (_. _. _. _. x. y. x y)";\r
364 ] ;;\r
365 \r
366 \r
367 print_hline();\r
368 print_endline "ALL DONE. "\r