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