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