]> matita.cs.unibo.it Git - fireball-separation.git/commitdiff
Initial commit from my pc
author <andrea.condoluci@unibo.it> <>
Mon, 12 Jun 2017 20:41:31 +0000 (22:41 +0200)
committer <andrea.condoluci@unibo.it> <>
Mon, 12 Jun 2017 20:41:31 +0000 (22:41 +0200)
14 files changed:
ocaml/Makefile
ocaml/andrea3.ml
ocaml/andrea3.mli [new file with mode: 0644]
ocaml/andrea4'.ml [new file with mode: 0644]
ocaml/andrea4.ml [new file with mode: 0644]
ocaml/andrea6.ml
ocaml/andrea7.ml [new file with mode: 0644]
ocaml/lambda4.ml
ocaml/lambda4b.ml [new file with mode: 0644]
ocaml/measure.ml [new file with mode: 0644]
ocaml/num.ml
ocaml/num.mli
ocaml/ptest.ml [new file with mode: 0644]
ocaml/tmp.ml [new file with mode: 0644]

index 3310c6e6e827a3511fb647d35743c195e6cf5ac6..b97d5afaef0e79f57d20bd836a7cf7a6ba39386e 100644 (file)
@@ -13,8 +13,8 @@ test.out: $(UTILS) lambda3.cmx test1.ml
 test34.out: $(UTILS) lambda3.cmx lambda4.cmx test.ml
        $(OCAMLC) -o test34.out $(LIB) $^
 
-andrea.out: $(UTILS) a.out andrea6.ml
-       $(OCAMLC) -o andrea.out $(LIB) $(UTILS) andrea6.ml
+andrea.out: $(UTILS) a.out andrea7.ml
+       $(OCAMLC) -o andrea.out $(LIB) $(UTILS) andrea7.ml
 
 #test2.out: $(UTILS) lambda3.ml test2.ml andrea
 #      ocamlc -o test2.out $(LIB) $(UTILS) lambda3.ml andrea4.ml test2.ml
index 27961070011a2638776c9bb78c7d4ca3cfdba129..a09ac42dd506d15f7d1004798263f92d4082862c 100644 (file)
@@ -47,7 +47,7 @@ let fancy_of_term t =
 let rec string_of_term =\r
   let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"] in\r
   let bound = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"] in\r
-  let string_of_int' n = if n >= 0 then List.nth free (n) else List.nth bound (-n-1) in\r
+  let string_of_int' n = string_of_int n in\r
   let rec string_of_var t =\r
     if Tvar t = dummy then "_" else if Tvar t = zero then "ZZ" else match t with\r
     | (n, None, _) -> (string_of_int' n)\r
@@ -70,7 +70,7 @@ let rec string_of_term =
 in let rec html_of_term =\r
   let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"; "h"; "i"; "j"] in\r
   let bound = ["x"; "y"; "z"; "w"; "q"] in\r
-  let string_of_int' n = if n >= 0 then List.nth free (n) else List.nth bound (-n-1) in\r
+  let string_of_int' n = string_of_int n in\r
   let rec string_of_var t =\r
     if Tvar t = dummy then "&num;" else if Tvar t = zero then "Z" else match t with\r
     | (n, None, _) -> (string_of_int' n)\r
@@ -96,28 +96,28 @@ in
 let fancy_of_nf t: Console.fancyobj =\r
 let rec print ?(l=[]) =\r
  function\r
-    `Var n -> Lambda3.print_name l n\r
+    `Var n -> Util.Vars.print_name l n\r
   | `N n -> string_of_int n\r
   | `Match(t,bs_lift,bs,args) ->\r
-     "([" ^ print ~l (t :> Lambda3.nf) ^\r
-     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Lambda3.lift bs_lift t)) !bs) ^ "] " ^\r
+     "([" ^ print ~l (t :> Num.nf) ^\r
+     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Num.lift bs_lift t)) !bs) ^ "] " ^\r
      String.concat " " (List.map (print ~l) args) ^ ")"\r
-  | `I(n,args) -> "(" ^ Lambda3.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"\r
-  | `Lam nf ->\r
-     let name = Lambda3.string_of_var (List.length l) in\r
-     "" ^ name ^ "." ^ print ~l:(name::l) (nf : Lambda3.nf)\r
+  | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"\r
+  | `Lam(_,nf) ->\r
+     let name = Util.Vars.string_of_var (List.length l) in\r
+     "" ^ name ^ "." ^ print ~l:(name::l) (nf : Num.nf)\r
 \r
 in let rec print_html ?(l=[]) =\r
  function\r
-    `Var n -> Lambda3.print_name l n\r
+    `Var n -> Util.Vars.print_name l n\r
   | `N n -> string_of_int n\r
   | `Match(t,bs_lift,bs,args) ->\r
-     "(<b>match</b> " ^ print_html ~l (t :> Lambda3.nf) ^\r
-     " <b>with</b> " ^ String.concat " <b>|</b> " (List.map (fun (n,t) -> string_of_int n ^ " <b>&rArr;</b> " ^ print_html ~l (Lambda3.lift bs_lift t)) !bs) ^ "..." (* Attenzion non sto stampando gli argomenti applicati! Perche' non ce ne sono mai *)\r
-  | `I(n,args) -> "(" ^ Lambda3.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print_html ~l) args)) ^ ")"\r
-  | `Lam nf ->\r
-     let name = Lambda3.string_of_var (List.length l) in\r
-     "&lambda;" ^ name ^ ". " ^ print_html ~l:(name::l) (nf : Lambda3.nf)\r
+     "(<b>match</b> " ^ print_html ~l (t :> Num.nf) ^\r
+     " <b>with</b> " ^ String.concat " <b>|</b> " (List.map (fun (n,t) -> string_of_int n ^ " <b>&rArr;</b> " ^ print_html ~l (Num.lift bs_lift t)) !bs) ^ "..." (* Attenzion non sto stampando gli argomenti applicati! Perche' non ce ne sono mai *)\r
+  | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print_html ~l) args)) ^ ")"\r
+  | `Lam(_,nf) ->\r
+     let name = Util.Vars.string_of_var (List.length l) in\r
+     "&lambda;" ^ name ^ ". " ^ print_html ~l:(name::l) (nf : Num.nf)\r
 in\r
   print t / print_html t\r
 ;;\r
@@ -235,29 +235,29 @@ let stupid_sort_uniq l = stupid_uniq (List.sort stupid_compare l);;
   - subs e' l'insieme dei sottotermini\r
   TODO: riscrivere la funzione per evitare/ottimizzare la ricorsione\r
  *)\r
-let crea_match k subs (acc : (term * Lambda3.nf) list) : term -> Lambda3.nf =\r
+let crea_match k subs (acc : (term * Num.nf) list) : term -> Num.nf =\r
   let req t = try List.assoc t acc with Not_found -> `Var 9999 in\r
   let aux t1 = (\r
   if t1 = dummy then `Var 99999 else\r
   (* let _ = print_term t1 in *)\r
   let cont = List.filter (fun t2 -> List.mem (Tapp(t1,t2)) subs) subs\r
   in if cont = [] then\r
-    try `N (Lambda3.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else\r
+    try `N (Util.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else\r
   let a = alive (hd t1) in\r
-    if a = 0 then `Lam (req (Tapp(t1, dummy)))\r
+    if a = 0 then `Lam (true, req (Tapp(t1, dummy)))\r
     else (\r
       let vars = (List.rev (mk_vars t1 (a-1) k)) @ [zero]\r
       (* in let _ = print_endline (String.concat " " (List.map string_of_term vars))\r
       in let _ = print_term (mk_apps dummy vars) *)\r
       in let vars = List.map req vars\r
-      in let vars = List.map (Lambda3.lift 1) vars (* forse lift non necessario *)\r
+      in let vars = List.map (Num.lift 1) vars (* forse lift non necessario *)\r
       in let vars = Listx.from_list vars\r
       in let body = `I(0, vars)\r
-      in let branches = List.map (fun t2 -> (Lambda3.index_of t2 subs, req (Tapp(t1, t2)))) cont\r
+      in let branches = List.map (fun t2 -> (Util.index_of t2 subs, req (Tapp(t1, t2)))) cont\r
       in let bs = ref(branches)\r
       in let lift = 1\r
       in let args = []\r
-      in `Lam (`Match(body, lift, bs, args))\r
+      in `Lam (true, `Match(body, lift, bs, args))\r
     )\r
   ) in aux\r
 ;;\r
@@ -270,14 +270,43 @@ let mk_zeros k =
 ;;\r
 \r
 let is_scott_n t n =\r
-  let open Lambda3 in let open Pure in\r
+  let open Pure.Pure in\r
   let rec aux n = function\r
   | L (L (A (V 1, L (V 0)))) -> n = 0\r
-  | L (L (A (V 0, t))) -> aux (n-1) t\r
+  | L (L (A (V 0, t))) -> assert (n > 0); aux (n-1) t\r
   | _ -> assert false\r
   in aux n t\r
 ;;\r
 \r
+let pure_subst delift_by_one what with_what =\r
+ let open Pure.Pure in\r
+ let rec aux l =\r
+  function\r
+   | A(t1,t2) -> A(aux l t1, aux l t2)\r
+   | V n ->\r
+       if n = what + l then\r
+        lift l with_what\r
+       else\r
+        V (if delift_by_one && n >= l then n-1 else n)\r
+   | L t -> L (aux (l+1) t)\r
+ in\r
+  aux 0\r
+;;\r
+\r
+let rec pure_whd =\r
+ let open Pure.Pure in\r
+ function\r
+  | A(t1, t2) ->\r
+     let t2 = pure_whd t2 in\r
+     let t1 = pure_whd t1 in\r
+      (match t1 with\r
+        | L f -> pure_whd (pure_subst true 0 t2 f)\r
+        | V _\r
+        | A _ -> A(t1,t2))\r
+  | V _\r
+  | L _ as t -> t\r
+;;\r
+\r
 (* do the magic *)\r
 let magic strings k h = (\r
   let tms = parse strings\r
@@ -309,29 +338,48 @@ let magic strings k h = (
   in let _ = List.iter (fun (x,y) -> print_endline (fancy_of_term x ^^ (" : " / " &#8614; ") ^^ fancy_of_nf y)) sigma\r
 \r
   in let _ = progress "controllo di purezza";\r
-  in let open Lambda3\r
-  in let ps, _ = Lambda3.parse' strings\r
-  in let ps = List.map (fun x -> Lambda3.mk_app x (`Var 1010)) ps\r
-  in let ps = List.map (fun t -> ToScott.t_of_nf (t :> nf)) ps\r
+  in let ps, _ = Num.parse' strings\r
+  in let ps = List.map (fun x -> Num.mk_app x (`Var 1010)) ps\r
+  in let ps = List.map (fun t -> Num.ToScott.t_of_nf (t :> Num.nf)) ps\r
   in let sigma = List.map (\r
-    function (Tvar(n,_,_), inst) -> n, ToScott.t_of_nf inst | _ -> assert false\r
+    function (Tvar(n,_,_), inst) -> n, Num.ToScott.t_of_nf inst | _ -> assert false\r
     ) sigma\r
   in let ps =\r
-    List.fold_left (fun ps (x,inst) -> List.map (Pure.subst false x inst) ps) ps sigma\r
+    List.fold_left (fun ps (x,inst) -> List.map (pure_subst false x inst) ps) ps sigma\r
   in let _ = List.iteri (fun i n ->\r
     (* print_string_endline ((string_of_int i) ^ ":: " ^ (Pure.print (Pure.whd n))); *)\r
-    (* assert (Pure.whd n = Scott.mk_n (Lambda3.index_of (List.nth tms' i) subs))) ps *)\r
-    assert (is_scott_n (Pure.whd n) (Lambda3.index_of (List.nth tms' i) subs))) ps\r
+    (* assert (Pure.whd n = Scott.mk_n (Util.index_of (List.nth tms' i) subs))) ps *)\r
+    assert (is_scott_n (pure_whd n) (Util.index_of (List.nth tms' i) subs))) ps\r
   in let _ = progress "fatto." in ()\r
 );;\r
 \r
+let no_subterms strings k h =\r
+  let tms = parse strings\r
+  in let tms = List.map (fun x -> Tapp(x, zero)) tms\r
+  in let tms' = List.map (setalive h) tms\r
+  in let tms' = List.map (translate k) tms'\r
+  in let tms' = List.map dummize tms'\r
+  in let progress s = print_bullet (fancy_of_string s)\r
+  in let _ = progress "traduzione completata"\r
+  (* in let _ = List.map print_term tms' *)\r
+  in let _ = progress "ordino i sottotermini"\r
+  in let subs = List.concat (List.map subterms tms')\r
+  in let subs = stupid_sort_uniq subs\r
+  (* metti gli zeri in testa, perche' vanno calcolati per primi *)\r
+  in let zeros = mk_zeros k\r
+  in let subs = (List.filter (fun t -> not (List.mem t zeros)) subs) @ (List.rev zeros)\r
+  in let subno = List.length subs\r
+  in let _ = progress ("sottotermini generati: " ^ string_of_int subno)\r
+  in subno\r
+;;\r
+\r
 let do_everything tms =\r
 let tms' = parse tms in\r
 let _ = List.iter print_term tms' in\r
 let k = compute_special_k tms' in\r
 let h = compute_special_h tms' in\r
 (* let _ = print_string_endline (string_of_int h) in *)\r
-magic tms k h\r
+no_subterms tms k h\r
 ;;\r
 \r
 let _ =\r
@@ -345,7 +393,7 @@ let _ =
   let k = compute_special_k tms' in\r
   let h = compute_special_h tms' in\r
   (* let _ = print_string_endline (string_of_int h) in *)\r
-  magic tms k h\r
+  no_subterms tms k h\r
 ;;\r
 \r
 (* type var' = (* unique name *) int * (int * term') option * (*dead*) bool option\r
diff --git a/ocaml/andrea3.mli b/ocaml/andrea3.mli
new file mode 100644 (file)
index 0000000..8ec0c9f
--- /dev/null
@@ -0,0 +1 @@
+val do_everything: string list -> int\r
diff --git a/ocaml/andrea4'.ml b/ocaml/andrea4'.ml
new file mode 100644 (file)
index 0000000..f734cca
--- /dev/null
@@ -0,0 +1,358 @@
+type var = (* unique name *) int * (int * term) option * (*level*) int\r
+and term =\r
+  | Tvar of var\r
+  | Tapp of term * term\r
+  | Tlam of int * term\r
+;;\r
+\r
+let zero = Tvar 1010;;\r
+let dummy = Tvar 333;;\r
+\r
+\r
+(* mk_app & subst implementano la beta *)\r
+let rec mk_app t1 t2 = match t1 with\r
+  | Tlam(v, t1') -> subst v t2 t1'\r
+  | _ -> Tapp(t1, t2, false)\r
+and subst v tv =\r
+  let rec aux = function\r
+  | Tapp(t1, t2, _) -> mk_app (aux t1) (aux t2)\r
+  | Tvar v' as t -> if v = v' then tv else t\r
+  | Tlam(v', t') as t -> if v = v' then t else Tlam(v', aux t')\r
+  in aux\r
+;;\r
+\r
+(* PARSING AND PRINTING *)\r
+\r
+let parse =\r
+  let rec minus1 = function\r
+    | Tvar n -> Tvar (n-1)\r
+    | Tapp(t1, t2, b) -> Tapp(minus1 t1, minus1 t2, b)\r
+    | Tlam(n, t) -> Tlam(n-1, minus1 t)\r
+  (* in let open Parser *)\r
+  in let rec myterm_of_term = function\r
+    | Parser.Var n -> Tvar n\r
+    | Parser.App(t1, t2) -> (*Tapp(myterm_of_term t1, myterm_of_term t2) WARNING! BETA DOWN HERE! *)\r
+                            mk_app (myterm_of_term t1) (myterm_of_term t2)\r
+    | Parser.Lam(t) -> minus1 (Tlam(0, myterm_of_term t))\r
+  in fun strs -> (\r
+    let (tms, free) = Parser.parse_many strs\r
+    in List.map myterm_of_term tms\r
+    )\r
+;;\r
+\r
+(* PRETTY PRINTING *)\r
+open Console;;\r
+\r
+let fancy_of_term t =\r
+let rec string_of_term =\r
+  let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"] in\r
+  let bound = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"] in\r
+  let string_of_int' n = if n >= 0 then "free" ^ string_of_int n else "bound" ^ string_of_int n  in\r
+  let rec string_of_var t =\r
+    if Tvar t = dummy then "_" else if Tvar t = zero then "ZZ" else match t with\r
+    | n -> string_of_int' n\r
+  and string_of_term_w_pars = function\r
+    | Tvar v -> string_of_var v\r
+    | Tapp(t1, t2, _) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")"\r
+    | Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")"\r
+  and string_of_term_no_pars_app = function\r
+    | Tapp(t1, t2,_) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2)\r
+    | _ as t -> string_of_term_w_pars t\r
+  and string_of_term_no_pars_lam = function\r
+    | Tlam(v, t) -> "λ" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t)\r
+    | _ as t -> string_of_term_no_pars t\r
+  and string_of_term_no_pars = function\r
+    | Tlam(_, _) as t -> string_of_term_no_pars_lam t\r
+    | _ as t -> string_of_term_no_pars_app t\r
+  in string_of_term_no_pars\r
+in let rec html_of_term =\r
+  let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"; "h"; "i"; "j"] in\r
+  let bound = ["x"; "y"; "z"; "w"; "q"] in\r
+  let string_of_int' n = if n >= 0 then List.nth free (n) else List.nth bound (-n-1) in\r
+  let rec string_of_var t =\r
+    if Tvar t = dummy then "&num;" else if Tvar t = zero then "Z" else string_of_int' t\r
+  and string_of_term_w_pars = function\r
+    | Tvar v -> string_of_var v\r
+    | Tapp(t1, t2,_) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")"\r
+    | Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")"\r
+  and string_of_term_no_pars_app = function\r
+    | Tapp(t1, t2,_) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2)\r
+    | _ as t -> string_of_term_w_pars t\r
+  and string_of_term_no_pars_lam = function\r
+    | Tlam(v, t) -> "&lambda;" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t)\r
+    | _ as t -> string_of_term_no_pars t\r
+  and string_of_term_no_pars = function\r
+    | Tlam(_, _) as t -> string_of_term_no_pars_lam t\r
+    | _ as t -> string_of_term_no_pars_app t\r
+  in string_of_term_no_pars\r
+in\r
+  string_of_term t / "html_of_term t"\r
+;;\r
+\r
+let fancy_of_nf t: Console.fancyobj =\r
+let rec print ?(l=[]) =\r
+ function\r
+    `Var n -> Util.Vars.print_name l n\r
+  | `N n -> string_of_int n\r
+  | `Match(t,bs_lift,bs,args) ->\r
+     "([" ^ print ~l (t :> Num.nf) ^\r
+     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Num.lift bs_lift t)) !bs) ^ "] " ^\r
+     String.concat " " (List.map (print ~l) args) ^ ")"\r
+  | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"\r
+  | `Lam(_,nf) ->\r
+     let name = Util.Vars.string_of_var (List.length l) in\r
+     "" ^ name ^ "." ^ print ~l:(name::l) (nf : Num.nf)\r
+\r
+(* in let rec print_html ?(l=[]) =\r
+ function\r
+    `Var n -> Lambda3.print_name l n\r
+  | `N n -> string_of_int n\r
+  | `Match(t,bs_lift,bs,args) ->\r
+     "(<b>match</b> " ^ print_html ~l (t :> Lambda3.nf) ^\r
+     " <b>with</b> " ^ String.concat " <b>|</b> " (List.map (fun (n,t) -> string_of_int n ^ " <b>&rArr;</b> " ^ print_html ~l (Lambda3.lift bs_lift t)) !bs) ^ "..." (* Attenzion non sto stampando gli argomenti applicati! Perche' non ce ne sono mai *)\r
+  | `I(n,args) -> "(" ^ Lambda3.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print_html ~l) args)) ^ ")"\r
+  | `Lam nf ->\r
+     let name = Lambda3.string_of_var (List.length l) in\r
+     "&lambda;" ^ name ^ ". " ^ print_html ~l:(name::l) (nf : Lambda3.nf) *)\r
+in\r
+  print t / print t\r
+;;\r
+\r
+let print_term t = print_endline (fancy_of_term t :> Console.fancyobj);;\r
+(*  *)\r
+\r
+\r
+let varcount = ref 11;;\r
+\r
+let freshvar () = (\r
+  varcount := (!varcount + 1);\r
+  !varcount\r
+);;\r
+\r
+\r
+\r
+(* magic ["x (x x x)"; "x (y. y x)"; "x x (y. y y (x x y))"] ;; *)\r
+(* magic ["((x x) (x. x))";"x x"];; *)\r
+\r
+let alive (_, _, n) = n;;\r
+let rec setalive c = function\r
+  | Tvar(a,b,_) as v -> if v <> zero && v <> dummy then Tvar(a,b,c) else v\r
+  | Tapp(a,b) -> Tapp(setalive c a, setalive c b)\r
+  | Tlam(n, t) -> Tlam(n, setalive c t)\r
+;;\r
+\r
+let mk_vars t lev =\r
+  let rec aux n =\r
+    if n = 0\r
+    then []\r
+    else Tvar(0, Some(n, t), lev) :: (aux (n-1))\r
+  in aux\r
+;;\r
+\r
+let mk_apps t ts = List.fold_right (fun x y -> mk_app y x) (List.rev ts) t;; (* which FOLD? FIXME *)\r
+\r
+\r
+let compute_special_k tms =\r
+  let rec aux k t = match t with\r
+    | Tvar _ -> 0\r
+    | Tapp(t1,t2) -> Pervasives.max (aux 0 t1) (aux 0 t2)\r
+    | Tlam(v,t) -> Pervasives.max (k+1) (aux (k + 1) t)\r
+  in List.fold_left (fun b a -> Pervasives.max (aux 0 a) b) 0 tms\r
+;;\r
+\r
+let compute_special_h tms =\r
+  let rec eat_lam = function\r
+    | Tlam(_,t) -> eat_lam t\r
+    | _ as t -> t\r
+  in\r
+  let rec aux t = match t with\r
+    | Tvar _ -> 0\r
+    | Tapp(t1,t2) -> Pervasives.max (aux t1) (aux t2)\r
+    | Tlam(v,t) -> 1 + (aux (eat_lam t))\r
+  in 1 + List.fold_left (fun b a -> Pervasives.max (aux a) b) 0 tms\r
+;;\r
+\r
+(* funzione di traduzione brutta & cattiva *)\r
+let translate k =\r
+  let rec aux = function\r
+  | Tlam _ -> assert false\r
+  | Tvar _ as v -> v\r
+  | Tapp(t1, t2) ->\r
+    let v = hd t1 in\r
+    let a = alive v in\r
+    let t1' = aux t1 in\r
+    let t2' = if a = 0\r
+      then t2\r
+      else mk_apps t2 ((List.rev (mk_vars t1' (a-1) k)) @ [zero])\r
+    in Tapp(t1', aux t2')\r
+  in aux\r
+;;\r
+\r
+(* sostituisce gli argomenti dummy (delle variabili morte) con 'dummy' *)\r
+let rec dummize = function\r
+  | Tlam _ -> assert false\r
+  | Tvar (a,Some(b,t), c) -> Tvar(a, Some (b, dummize t), c)\r
+  | Tvar _ as v -> v\r
+  | Tapp(t1, t2) ->\r
+    if alive (hd t1) = 0\r
+    then Tapp(dummize t1, dummy)\r
+    else Tapp(dummize t1, dummize t2)\r
+;;\r
+\r
+(* lista di sottotermini applicativi *)\r
+let rec subterms = function\r
+  | Tlam _ -> assert false\r
+  | Tvar _ as v -> [v]\r
+  | Tapp(t1, t2) -> Tapp(t1, t2) :: ((subterms t1) @ (subterms t2))\r
+;;\r
+\r
+(* filtra dai sottotermini le variabili *)\r
+let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;;\r
+\r
+\r
+let rec stupid_uniq = function\r
+  | [] -> []\r
+  | x::xs -> if List.mem x xs then (stupid_uniq xs) else x::(stupid_uniq xs)\r
+;;\r
+let stupid_compare a b =\r
+  let rec size = function\r
+    | Tvar(_,None,_) -> 0\r
+    | Tvar(_,Some(_,t),_) -> 1 + size t\r
+    | Tapp(t1,t2) -> 1 + size t1 + size t2\r
+    | Tlam _ -> assert false\r
+  in compare (size a) (size b)\r
+;;\r
+let stupid_sort_uniq l = stupid_uniq (List.sort stupid_compare l);;\r
+\r
+(* crea i match ricorsivamente.\r
+  - k e' lo special-K\r
+  - subs e' l'insieme dei sottotermini\r
+  TODO: riscrivere la funzione per evitare/ottimizzare la ricorsione\r
+ *)\r
+let crea_match k subs (acc : (term * Lambda3.nf) list) : term -> Lambda3.nf =\r
+  let req t = try List.assoc t acc with Not_found -> `Var 9999 in\r
+  let aux t1 = (\r
+  if t1 = dummy then `Var 99999 else\r
+  (* let _ = print_term t1 in *)\r
+  let cont = List.filter (fun t2 -> List.mem (Tapp(t1,t2)) subs) subs\r
+  in if cont = [] then\r
+    try `N (Lambda3.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else\r
+  let a = alive (hd t1) in\r
+    if a = 0 then `Lam (req (Tapp(t1, dummy)))\r
+    else (\r
+      let vars = (List.rev (mk_vars t1 (a-1) k)) @ [zero]\r
+      (* in let _ = print_endline (String.concat " " (List.map string_of_term vars))\r
+      in let _ = print_term (mk_apps dummy vars) *)\r
+      in let vars = List.map req vars\r
+      in let vars = List.map (Lambda3.lift 1) vars (* forse lift non necessario *)\r
+      in let vars = Listx.from_list vars\r
+      in let body = `I(0, vars)\r
+      in let branches = List.map (fun t2 -> (Lambda3.index_of t2 subs, req (Tapp(t1, t2)))) cont\r
+      in let bs = ref(branches)\r
+      in let lift = 1\r
+      in let args = []\r
+      in `Lam (`Match(body, lift, bs, args))\r
+    )\r
+  ) in aux\r
+;;\r
+\r
+let mk_zeros k =\r
+  let rec aux n prev =\r
+    if n = 0 then [zero]\r
+    else let prev = aux (n-1) prev in let x = mk_app (List.hd prev) dummy in x :: prev\r
+  in aux (k+1) []\r
+;;\r
+\r
+let is_scott_n t n =\r
+  let open Lambda3 in let open Pure in\r
+  let rec aux n = function\r
+  | L (L (A (V 1, L (V 0)))) -> n = 0\r
+  | L (L (A (V 0, t))) -> aux (n-1) t\r
+  | _ -> assert false\r
+  in aux n t\r
+;;\r
+\r
+(* do the magic *)\r
+let magic strings k h = (\r
+  let tms = parse strings\r
+  in let tms = List.map (fun x -> Tapp(x, zero)) tms\r
+  in let tms' = List.map (setalive h) tms\r
+  in let tms' = List.map (translate k) tms'\r
+  in let tms' = List.map dummize tms'\r
+  (* in let bullet = ">" / "&bullet;" *)\r
+  (* in let progress s = print_endline (bullet ^^ fancy_of_string s) *)\r
+  in let progress = print_h1\r
+  in let _ = progress "traduzione completata"\r
+  (* in let _ = List.map print_term tms' *)\r
+  in let _ = progress "ordino i sottotermini"\r
+  in let subs = List.concat (List.map subterms tms')\r
+  in let subs = stupid_sort_uniq subs\r
+  (* metti gli zeri in testa, perche' vanno calcolati per primi *)\r
+  in let zeros = mk_zeros k\r
+  in let subs = (List.filter (fun t -> not (List.mem t zeros)) subs) @ (List.rev zeros)\r
+  in let _ = progress ("sottotermini generati: " ^ string_of_int (List.length subs))\r
+  in let vars = vars subs\r
+  (* in let _ = List.iter print_term subs *)\r
+  (* in let _ = 0/0 *)\r
+  in let fv = List.filter (function Tvar(_, None, _) as v -> v <> dummy | _ -> false) vars\r
+  (* in let _ = print_string ("> free vars: " ^ String.concat ", " (List.map (string_of_term) fv)) *)\r
+  in let _ = progress "sto creando i match"\r
+  (* in let sigma = List.map (fun x -> x, crea_match k subs x) fv *)\r
+  in let f t acc = let res = crea_match k subs acc t in (t,res)::acc\r
+  in let acc = List.fold_right f subs []\r
+  in let sigma = List.filter (fun (t,res) -> List.mem t fv) acc\r
+  in let _ = progress "match creati"\r
+  in let _ = List.iter (fun (x,y) -> print_endline (fancy_of_term x ^^ (" : " / " &#8614; ") ^^ fancy_of_nf y)) sigma\r
+\r
+  in let _ = progress "controllo di purezza";\r
+  in let open Lambda3\r
+  in let ps, _ = Lambda3.parse' strings\r
+  in let ps = List.map (fun x -> Lambda3.mk_app x (`Var 1010)) ps\r
+  in let ps = List.map (fun t -> ToScott.t_of_nf (t :> nf)) ps\r
+  in let sigma = List.map (\r
+    function (Tvar(n,_,_), inst) -> n, ToScott.t_of_nf inst | _ -> assert false\r
+    ) sigma\r
+  in let ps =\r
+    List.fold_left (fun ps (x,inst) -> List.map (Pure.subst false x inst) ps) ps sigma\r
+  in let _ = List.iteri (fun i n ->\r
+    (* print_string_endline ((string_of_int i) ^ ":: " ^ (Pure.print (Pure.whd n))); *)\r
+    (* assert (Pure.whd n = Scott.mk_n (Lambda3.index_of (List.nth tms' i) subs))) ps *)\r
+    assert (is_scott_n (Pure.whd n) (Lambda3.index_of (List.nth tms' i) subs))) ps\r
+  in let _ = progress "fatto." in ()\r
+);;\r
+\r
+let do_everything tms =\r
+let tms' = parse tms in\r
+let k = compute_special_k tms' in\r
+let h = compute_special_h tms' in\r
+(* let _ = print_string_endline (string_of_int h) in *)\r
+magic tms k h\r
+;;\r
+\r
+let _ =\r
+  let tms = ["a a"; "a b"; "b a"; "b (x. y.x y a)"] in\r
+  (* 1 2 *)\r
+  (* let tms = ["x c" ; "b (x c d e)"; "b"] in *)\r
+  (* 0 1 *)\r
+  (* let tms = ["x x x"] in *)\r
+  let tms' = parse tms in\r
+  let k = compute_special_k tms' in\r
+  let h = compute_special_h tms' in\r
+  (* let _ = print_string_endline (string_of_int h) in *)\r
+  magic tms k h\r
+;;\r
+\r
+(* type var' = (* unique name *) int * (int * term') option * (*dead*) bool option\r
+and term' =\r
+  | Tvar' of var'\r
+  | Tapp' of term' * term' * (* active *) bool\r
+  | Tlam' of int * term'\r
+;;\r
+\r
+let rec iter mustapply =\r
+  let aux = function\r
+  | Tvar'(n, Some(m,t), b) -> Tvar(n, Some(m, aux t), b)\r
+  | Tvar' _ as v -> v\r
+  | Tapp'(t1, t2, b) -> if b &&\r
+  in aux\r
+;; *)\r
diff --git a/ocaml/andrea4.ml b/ocaml/andrea4.ml
new file mode 100644 (file)
index 0000000..4b7e448
--- /dev/null
@@ -0,0 +1,637 @@
+(* type var = (* unique name *) int * (int * term) option * (*level*) int *)\r
+type term =\r
+  | Tvar of int\r
+  | Tapp of term * term * bool\r
+  | Tlam of int * term\r
+;;\r
+\r
+let zero = Tvar 1010;;\r
+let dummy = Tvar 333;;\r
+\r
+\r
+(* mk_app & subst implementano la beta *)\r
+let rec mk_app t1 t2 = match t1 with\r
+  | Tlam(v, t1') -> subst v t2 t1'\r
+  | _ -> Tapp(t1, t2, false)\r
+and subst v tv =\r
+  let rec aux = function\r
+  | Tapp(t1, t2, _) -> mk_app (aux t1) (aux t2)\r
+  | Tvar v' as t -> if v = v' then tv else t\r
+  | Tlam(v', t') as t -> if v = v' then t else Tlam(v', aux t')\r
+  in aux\r
+;;\r
+\r
+(* PARSING AND PRINTING *)\r
+\r
+let parse =\r
+  let rec minus1 = function\r
+    | Tvar n -> Tvar (n-1)\r
+    | Tapp(t1, t2, b) -> Tapp(minus1 t1, minus1 t2, b)\r
+    | Tlam(n, t) -> Tlam(n-1, minus1 t)\r
+  (* in let open Parser *)\r
+  in let rec myterm_of_term = function\r
+    | Parser.Var n -> Tvar n\r
+    | Parser.App(t1, t2) -> (*Tapp(myterm_of_term t1, myterm_of_term t2) WARNING! BETA DOWN HERE! *)\r
+                            mk_app (myterm_of_term t1) (myterm_of_term t2)\r
+    | Parser.Lam(t) -> minus1 (Tlam(0, myterm_of_term t))\r
+  in fun strs -> (\r
+    let (tms, free) = Parser.parse_many strs\r
+    in List.map myterm_of_term tms\r
+    )\r
+;;\r
+\r
+(* PRETTY PRINTING *)\r
+open Console;;\r
+\r
+let fancy_of_term t =\r
+let rec string_of_term =\r
+  let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"] in\r
+  let bound = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"] in\r
+  let string_of_int' n = if n >= 0 then "free" ^ string_of_int n else "bound" ^ string_of_int n  in\r
+  let rec string_of_var t =\r
+    if Tvar t = dummy then "_" else if Tvar t = zero then "ZZ" else match t with\r
+    | n -> string_of_int' n\r
+  and string_of_term_w_pars = function\r
+    | Tvar v -> string_of_var v\r
+    | Tapp(t1, t2, _) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")"\r
+    | Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")"\r
+  and string_of_term_no_pars_app = function\r
+    | Tapp(t1, t2,_) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2)\r
+    | _ as t -> string_of_term_w_pars t\r
+  and string_of_term_no_pars_lam = function\r
+    | Tlam(v, t) -> "λ" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t)\r
+    | _ as t -> string_of_term_no_pars t\r
+  and string_of_term_no_pars = function\r
+    | Tlam(_, _) as t -> string_of_term_no_pars_lam t\r
+    | _ as t -> string_of_term_no_pars_app t\r
+  in string_of_term_no_pars\r
+in let rec html_of_term =\r
+  let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"; "h"; "i"; "j"] in\r
+  let bound = ["x"; "y"; "z"; "w"; "q"] in\r
+  let string_of_int' n = if n >= 0 then List.nth free (n) else List.nth bound (-n-1) in\r
+  let rec string_of_var t =\r
+    if Tvar t = dummy then "&num;" else if Tvar t = zero then "Z" else string_of_int' t\r
+  and string_of_term_w_pars = function\r
+    | Tvar v -> string_of_var v\r
+    | Tapp(t1, t2,_) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")"\r
+    | Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")"\r
+  and string_of_term_no_pars_app = function\r
+    | Tapp(t1, t2,_) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2)\r
+    | _ as t -> string_of_term_w_pars t\r
+  and string_of_term_no_pars_lam = function\r
+    | Tlam(v, t) -> "&lambda;" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t)\r
+    | _ as t -> string_of_term_no_pars t\r
+  and string_of_term_no_pars = function\r
+    | Tlam(_, _) as t -> string_of_term_no_pars_lam t\r
+    | _ as t -> string_of_term_no_pars_app t\r
+  in string_of_term_no_pars\r
+in\r
+  string_of_term t / "html_of_term t"\r
+;;\r
+\r
+let fancy_of_nf t: Console.fancyobj =\r
+let rec print ?(l=[]) =\r
+ function\r
+    `Var n -> Util.Vars.print_name l n\r
+  | `N n -> string_of_int n\r
+  | `Match(t,bs_lift,bs,args) ->\r
+     "([" ^ print ~l (t :> Num.nf) ^\r
+     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Num.lift bs_lift t)) !bs) ^ "] " ^\r
+     String.concat " " (List.map (print ~l) args) ^ ")"\r
+  | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"\r
+  | `Lam(_,nf) ->\r
+     let name = Util.Vars.string_of_var (List.length l) in\r
+     "" ^ name ^ "." ^ print ~l:(name::l) (nf : Num.nf)\r
+\r
+(* in let rec print_html ?(l=[]) =\r
+ function\r
+    `Var n -> Lambda3.print_name l n\r
+  | `N n -> string_of_int n\r
+  | `Match(t,bs_lift,bs,args) ->\r
+     "(<b>match</b> " ^ print_html ~l (t :> Lambda3.nf) ^\r
+     " <b>with</b> " ^ String.concat " <b>|</b> " (List.map (fun (n,t) -> string_of_int n ^ " <b>&rArr;</b> " ^ print_html ~l (Lambda3.lift bs_lift t)) !bs) ^ "..." (* Attenzion non sto stampando gli argomenti applicati! Perche' non ce ne sono mai *)\r
+  | `I(n,args) -> "(" ^ Lambda3.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print_html ~l) args)) ^ ")"\r
+  | `Lam nf ->\r
+     let name = Lambda3.string_of_var (List.length l) in\r
+     "&lambda;" ^ name ^ ". " ^ print_html ~l:(name::l) (nf : Lambda3.nf) *)\r
+in\r
+  print t / print t\r
+;;\r
+\r
+let print_term t = print_endline (fancy_of_term t :> Console.fancyobj);;\r
+(*  *)\r
+\r
+\r
+let varcount = ref 11;;\r
+\r
+let freshvar () = (\r
+  varcount := (!varcount + 1);\r
+  !varcount\r
+);;\r
+\r
+let find_applicative =\r
+  let rec aux = function\r
+  | Tapp(t1, Tlam _, _) -> Some t1\r
+  | Tapp(t1, t2, _) ->\r
+    (match aux t1 with\r
+    | None -> aux t2\r
+    | _ as r -> r)\r
+  | _-> None\r
+  in let rec aux2 = function\r
+    | [] -> None\r
+    | x::xs -> (match aux x with\r
+      | None -> aux2 xs\r
+      | _ as result -> result\r
+    )\r
+  in aux2\r
+;;\r
+\r
+let mk_apps t ts = List.fold_right (fun x y -> mk_app y x) (List.rev ts) t;; (* which FOLD? FIXME *)\r
+\r
+let rec hd = function | Tvar _ as x -> x | Tapp(t, _, _) -> hd t | _ -> assert false;;\r
+\r
+let rec set_applied =\r
+  function\r
+  | Tvar _ as v -> v\r
+  | Tlam _ -> assert false\r
+  | Tapp(t1,t2,_) -> Tapp(set_applied t1, set_applied t2, true)\r
+;;\r
+\r
+let rec constant a n =\r
+  if n = 0 then [] else a:: (constant a (n-1))\r
+;;\r
+\r
+let rec mk_dummies k t =\r
+  set_applied (mk_apps t (constant dummy (k+1)))\r
+;;\r
+\r
+let rec make_lambda_zero k =\r
+  if k = 0 then mk_dummies (k+1) zero else Tlam(0, make_lambda_zero (k-1))\r
+;;\r
+\r
+let mk_vars n =\r
+  let rec aux n =\r
+    if n = 0\r
+    then []\r
+    else (Tvar (freshvar ())) :: (aux (n-1))\r
+  in aux n @ [make_lambda_zero (n+1)]\r
+;;\r
+\r
+let apply a vars =\r
+  let rec aux = function\r
+  | Tapp(t1, t2, b) ->\r
+    if t1 = a\r
+    then (assert (not b); Tapp(aux t1, mk_apps' t2 vars, true))\r
+    else Tapp(aux t1, aux t2, b)\r
+  | _ as t -> t\r
+  and mk_apps' t vars =\r
+    if t = zero\r
+    then mk_dummies (List.length vars - 1) t\r
+    else aux (mk_apps t vars)\r
+  in aux\r
+;;\r
+\r
+let round k (app_map, tms) =\r
+  match find_applicative tms with\r
+  | None -> raise Not_found\r
+  | Some a ->\r
+    let vars = mk_vars k in\r
+    let f = apply a vars in\r
+    let app_map = (a, vars) :: (List.map (fun (x,y) -> f x, y) app_map)\r
+    in (app_map, List.map f tms)\r
+;;\r
+\r
+let ends_with t1 t2 = match t1 with\r
+  | Tapp(_, t, _) -> t = t2\r
+  | _ -> false\r
+;;\r
+\r
+let rec last_round k (app_map, forbidden, t) =\r
+  let mk_apps' forbidden t vars =\r
+    if List.mem t forbidden\r
+    then mk_dummies (List.length vars - 1) t\r
+    else mk_apps t vars\r
+  (* in let rec already_applied = function\r
+    | Tapp(_, t) -> t = zero || t = dummy || hd t = zero\r
+    | _ -> false *)\r
+  in if ends_with t dummy then (app_map, forbidden, t) else (match t with\r
+  | Tapp(t1, t2, b) ->\r
+    if b\r
+    then\r
+      let app_map, forbidden, t1 = last_round k (app_map, forbidden, t1)\r
+      in let app_map, forbidden, t2 = last_round k (app_map, forbidden, t2)\r
+      in app_map, forbidden, Tapp(t1, t2, b)\r
+    else\r
+      let app_map, forbidden, t1 = last_round k (app_map, forbidden, t1)\r
+      in let app_map, forbidden, t2 =\r
+        try\r
+            let vars = List.assoc t1 app_map\r
+            in last_round k (app_map, forbidden, (mk_apps' forbidden t2 vars))\r
+          with Not_found ->\r
+            let vars = mk_vars k in\r
+            let app_map = (t1, vars) :: app_map in\r
+            last_round k (app_map, (vars @ forbidden), (mk_apps' forbidden t2 vars))\r
+      in app_map, forbidden, Tapp(t1, t2, true)\r
+  | _ as t -> app_map, forbidden, t\r
+  )\r
+;;\r
+\r
+let fixpoint f =\r
+  let rec aux x = try\r
+    let y = f x in aux y\r
+  with Not_found -> x\r
+  in aux\r
+;;\r
+\r
+(* lista di sottotermini applicativi *)\r
+let rec subterms = function\r
+  | Tlam _ -> assert false\r
+  | Tvar _ as v -> [v]\r
+  | Tapp(t1, t2, b) -> Tapp(t1, t2, b) :: ((subterms t1) @ (subterms t2))\r
+;;\r
+\r
+(* filtra dai sottotermini le variabili *)\r
+let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;;\r
+\r
+let stupid_sort_uniq map l =\r
+  let rec stupid_uniq = function\r
+    | [] -> []\r
+    | x::xs -> if List.mem x xs then (stupid_uniq xs) else x::(stupid_uniq xs)\r
+  in let stupid_compare a b =\r
+    let rec size = function\r
+      | Tvar n as v -> if v = zero then 0 else (\r
+        try\r
+          let t, _ = List.find (fun (_,vars) -> List.mem v vars) map\r
+          in 1 + size t\r
+        with Not_found -> 1 + n)\r
+      | Tapp(t1,t2,_) -> 1 + size t1 + size t2\r
+      | Tlam _ -> assert false\r
+    in compare (size a) (size b)\r
+  in stupid_uniq (List.sort stupid_compare l)\r
+;;\r
+\r
+(* crea i match ricorsivamente.\r
+  - k e' lo special-K\r
+  - subs e' l'insieme dei sottotermini\r
+  TODO: riscrivere la funzione per evitare/ottimizzare la ricorsione\r
+ *)\r
+let crea_match subs map forbidden (acc : (term * Num.nf) list) : term -> Num.nf =\r
+  let req t = try List.assoc t acc with Not_found -> `Var 9999 in\r
+  let aux t1 = (\r
+  if t1 = dummy then `Var 99999 else\r
+  (* let _ = print_term t1 in *)\r
+  let cont = List.filter (fun t2 -> List.mem (Tapp(t1,t2,true)) subs) subs\r
+  in if cont = [] then\r
+    try `N (Util.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else\r
+\r
+    if List.mem (hd t1) forbidden then `Lam (true,req (Tapp(t1, dummy, true)))\r
+    else (\r
+      let vars = List.assoc t1 map\r
+      (* in let _ = print_endline (String.concat " " (List.map string_of_term vars))\r
+      in let _ = print_term (mk_apps dummy vars) *)\r
+      in let vars = List.map req vars\r
+      in let vars = List.map (Num.lift 1) vars (* forse lift non necessario *)\r
+      in let vars = Listx.from_list vars\r
+      in let body = `I(0, vars)\r
+      in let branches = List.map (fun t2 -> (Util.index_of t2 subs, req (Tapp(t1, t2, true)))) cont\r
+      in let bs = ref(branches)\r
+      in let lift = 1\r
+      in let args = []\r
+      in `Lam (true, `Match(body, lift, bs, args))\r
+    )\r
+  ) in aux\r
+;;\r
+\r
+(* filtra dai sottotermini le variabili *)\r
+let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;;\r
+\r
+let mk_zeros k =\r
+  let rec aux n prev =\r
+    if n = 0 then [zero]\r
+    else let prev = aux (n-1) prev in let x = mk_app (List.hd prev) dummy in x :: prev\r
+  in aux (k+1) []\r
+;;\r
+\r
+let rec freevars = function\r
+  | Tvar _ as v -> [v]\r
+  | Tlam(v,t) -> List.filter (fun x-> x <> Tvar v) (freevars t)\r
+  | Tapp(t1,t2,_) -> (freevars t1) @ (freevars t2)\r
+;;\r
+\r
+open Pure;;\r
+\r
+let is_scott_n t n =\r
+  let open Lambda4 in let open Pure in\r
+  let rec aux n = function\r
+  | L (L (A (V 1, L (V 0)))) -> n = 0\r
+  | L (L (A (V 0, t))) -> aux (n-1) t\r
+  | _ -> assert false\r
+  in aux n t\r
+;;\r
+let is_scott =\r
+  let open Lambda4 in let open Pure in\r
+  let rec aux = function\r
+  | L (L (A (V 1, L (V 0)))) -> 0\r
+  | L (L (A (V 0, t))) -> 1 + aux t\r
+  | _ -> assert false\r
+  in aux\r
+;;\r
+\r
+let compute_special_k tms =\r
+  let rec aux k t = match t with\r
+    | Tvar _ -> 0\r
+    | Tapp(t1,t2,_) -> Pervasives.max (aux 0 t1) (aux 0 t2)\r
+    | Tlam(v,t) -> Pervasives.max (k+1) (aux (k + 1) t)\r
+  in List.fold_left (fun b a -> Pervasives.max (aux 0 a) b) 0 tms\r
+;;\r
+\r
+let magic strings =\r
+  let rec map_helper_3 a b f =\r
+    function\r
+    | [] -> a, b, []\r
+    | c::cs ->\r
+      let a, b, d = f (a, b, c) in\r
+      let a, b, ds = map_helper_3 a b f cs in\r
+      a, b, (d::ds)\r
+  in let _ = print_hline ()\r
+  in let tms = parse strings\r
+  in let k = compute_special_k tms\r
+  in let zero' = make_lambda_zero (k+1)\r
+  in let tms = List.map (fun x -> Tapp(x, zero', false)) tms\r
+  in let fv = Util.sort_uniq (List.concat (List.map freevars tms))\r
+  in let (map, tms') = fixpoint (round k) ([], tms)\r
+  (* in let _ = print_string_endline "map1 "; List.iter (fun (t,_) -> print_term t) map; print_string_endline "ok1" *)\r
+  in let _ = List.map print_term tms'\r
+\r
+  in let map1 = List.map fst map\r
+  in let map2 = List.map snd map\r
+  in let map_new, forbidden, map1' = map_helper_3 [] [zero] (last_round k) map1\r
+\r
+  in let map = map_new @ (List.combine map1' map2)\r
+  (* in let _ = print_string_endline "map2 "; List.iter (fun (t,_) -> print_term t) map; print_string_endline "ok2" *)\r
+  in let map, forbidden, tms' = map_helper_3 map forbidden (last_round k) tms'\r
+\r
+  in let _ = List.map print_term tms'\r
+  in let subs = List.concat (List.map subterms tms')\r
+  in let subs = stupid_sort_uniq map subs\r
+  (* metti gli zeri in testa, perche' vanno calcolati per primi *)\r
+  in let zeros = mk_zeros k\r
+  in let subs = (List.filter (fun t -> not (List.mem t zeros)) subs) @ (List.rev zeros)\r
+\r
+  (* in let _ = print_string_endline " subs"; List.iter print_term subs *)\r
+  (* in let _ = print_string_endline "map "; List.iter (fun (t,_) -> print_term t) map; print_string_endline "ok" *)\r
+\r
+  in let f t acc = let res = crea_match subs map forbidden acc t in (t,res)::acc\r
+  in let acc = List.fold_right f subs []\r
+\r
+  in let sigma = List.filter (fun (t,res) -> List.mem t fv) acc\r
+  in let _ = List.iter (fun (x,y) -> print_endline (fancy_of_term x ^^ (" : " / " &#8614; ") ^^ fancy_of_nf y)) sigma\r
+\r
+  in let _ = print_string_endline "controllo di purezza";\r
+  (* in let open Num *)\r
+  in let ps, _ = Num.parse' strings\r
+  in let ps = List.map (fun x -> Num.mk_app x (`Var 1010)) ps\r
+  in let ps = List.map (fun t -> Num.ToScott.t_of_nf (t :> Num.nf)) ps\r
+  in let sigma = List.map (\r
+    function (Tvar n , inst) -> n, Num.ToScott.t_of_nf inst | _ -> assert false\r
+    ) sigma\r
+  (* in let ps =\r
+    List.fold_left (fun ps (x,inst) -> List.map (Pure.subst false x inst) ps) ps sigma\r
+  in let _ = List.iteri (fun i n ->\r
+    print_string_endline ("X " ^ Pure.print (Pure.whd n));\r
+    (* assert (is_scott_n (Pure.whd n) (Lambda3.index_of (List.nth tms' i) subs)) *)\r
+    is_scott (Pure.whd n); ()\r
+    ) ps *)\r
+  in ()\r
+;;\r
+\r
+\r
+(* magic ["x (x x x)"; "x (y. y x)"; "x x (y. y y (x x y))"] ;; *)\r
+magic ["((x x) (x. x))";"x x"];;\r
+\r
+(*\r
+\r
+let alive (_, _, n) = n;;\r
+let rec setalive c = function\r
+  | Tvar(a,b,_) as v -> if v <> zero && v <> dummy then Tvar(a,b,c) else v\r
+  | Tapp(a,b) -> Tapp(setalive c a, setalive c b)\r
+  | Tlam(n, t) -> Tlam(n, setalive c t)\r
+;;\r
+\r
+let mk_vars t lev =\r
+  let rec aux n =\r
+    if n = 0\r
+    then []\r
+    else Tvar(0, Some(n, t), lev) :: (aux (n-1))\r
+  in aux\r
+;;\r
+\r
+let mk_apps t ts = List.fold_right (fun x y -> mk_app y x) (List.rev ts) t;; (* which FOLD? FIXME *)\r
+\r
+\r
+let compute_special_k tms =\r
+  let rec aux k t = match t with\r
+    | Tvar _ -> 0\r
+    | Tapp(t1,t2) -> Pervasives.max (aux 0 t1) (aux 0 t2)\r
+    | Tlam(v,t) -> Pervasives.max (k+1) (aux (k + 1) t)\r
+  in List.fold_left (fun b a -> Pervasives.max (aux 0 a) b) 0 tms\r
+;;\r
+\r
+let compute_special_h tms =\r
+  let rec eat_lam = function\r
+    | Tlam(_,t) -> eat_lam t\r
+    | _ as t -> t\r
+  in\r
+  let rec aux t = match t with\r
+    | Tvar _ -> 0\r
+    | Tapp(t1,t2) -> Pervasives.max (aux t1) (aux t2)\r
+    | Tlam(v,t) -> 1 + (aux (eat_lam t))\r
+  in 1 + List.fold_left (fun b a -> Pervasives.max (aux a) b) 0 tms\r
+;;\r
+\r
+(* funzione di traduzione brutta & cattiva *)\r
+let translate k =\r
+  let rec aux = function\r
+  | Tlam _ -> assert false\r
+  | Tvar _ as v -> v\r
+  | Tapp(t1, t2) ->\r
+    let v = hd t1 in\r
+    let a = alive v in\r
+    let t1' = aux t1 in\r
+    let t2' = if a = 0\r
+      then t2\r
+      else mk_apps t2 ((List.rev (mk_vars t1' (a-1) k)) @ [zero])\r
+    in Tapp(t1', aux t2')\r
+  in aux\r
+;;\r
+\r
+(* sostituisce gli argomenti dummy (delle variabili morte) con 'dummy' *)\r
+let rec dummize = function\r
+  | Tlam _ -> assert false\r
+  | Tvar (a,Some(b,t), c) -> Tvar(a, Some (b, dummize t), c)\r
+  | Tvar _ as v -> v\r
+  | Tapp(t1, t2) ->\r
+    if alive (hd t1) = 0\r
+    then Tapp(dummize t1, dummy)\r
+    else Tapp(dummize t1, dummize t2)\r
+;;\r
+\r
+(* lista di sottotermini applicativi *)\r
+let rec subterms = function\r
+  | Tlam _ -> assert false\r
+  | Tvar _ as v -> [v]\r
+  | Tapp(t1, t2) -> Tapp(t1, t2) :: ((subterms t1) @ (subterms t2))\r
+;;\r
+\r
+(* filtra dai sottotermini le variabili *)\r
+let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;;\r
+\r
+\r
+let rec stupid_uniq = function\r
+  | [] -> []\r
+  | x::xs -> if List.mem x xs then (stupid_uniq xs) else x::(stupid_uniq xs)\r
+;;\r
+let stupid_compare a b =\r
+  let rec size = function\r
+    | Tvar(_,None,_) -> 0\r
+    | Tvar(_,Some(_,t),_) -> 1 + size t\r
+    | Tapp(t1,t2) -> 1 + size t1 + size t2\r
+    | Tlam _ -> assert false\r
+  in compare (size a) (size b)\r
+;;\r
+let stupid_sort_uniq l = stupid_uniq (List.sort stupid_compare l);;\r
+\r
+(* crea i match ricorsivamente.\r
+  - k e' lo special-K\r
+  - subs e' l'insieme dei sottotermini\r
+  TODO: riscrivere la funzione per evitare/ottimizzare la ricorsione\r
+ *)\r
+let crea_match k subs (acc : (term * Lambda3.nf) list) : term -> Lambda3.nf =\r
+  let req t = try List.assoc t acc with Not_found -> `Var 9999 in\r
+  let aux t1 = (\r
+  if t1 = dummy then `Var 99999 else\r
+  (* let _ = print_term t1 in *)\r
+  let cont = List.filter (fun t2 -> List.mem (Tapp(t1,t2)) subs) subs\r
+  in if cont = [] then\r
+    try `N (Lambda3.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else\r
+  let a = alive (hd t1) in\r
+    if a = 0 then `Lam (req (Tapp(t1, dummy)))\r
+    else (\r
+      let vars = (List.rev (mk_vars t1 (a-1) k)) @ [zero]\r
+      (* in let _ = print_endline (String.concat " " (List.map string_of_term vars))\r
+      in let _ = print_term (mk_apps dummy vars) *)\r
+      in let vars = List.map req vars\r
+      in let vars = List.map (Lambda3.lift 1) vars (* forse lift non necessario *)\r
+      in let vars = Listx.from_list vars\r
+      in let body = `I(0, vars)\r
+      in let branches = List.map (fun t2 -> (Lambda3.index_of t2 subs, req (Tapp(t1, t2)))) cont\r
+      in let bs = ref(branches)\r
+      in let lift = 1\r
+      in let args = []\r
+      in `Lam (`Match(body, lift, bs, args))\r
+    )\r
+  ) in aux\r
+;;\r
+\r
+let mk_zeros k =\r
+  let rec aux n prev =\r
+    if n = 0 then [zero]\r
+    else let prev = aux (n-1) prev in let x = mk_app (List.hd prev) dummy in x :: prev\r
+  in aux (k+1) []\r
+;;\r
+\r
+let is_scott_n t n =\r
+  let open Lambda3 in let open Pure in\r
+  let rec aux n = function\r
+  | L (L (A (V 1, L (V 0)))) -> n = 0\r
+  | L (L (A (V 0, t))) -> aux (n-1) t\r
+  | _ -> assert false\r
+  in aux n t\r
+;;\r
+\r
+(* do the magic *)\r
+let magic strings k h = (\r
+  let tms = parse strings\r
+  in let tms = List.map (fun x -> Tapp(x, zero)) tms\r
+  in let tms' = List.map (setalive h) tms\r
+  in let tms' = List.map (translate k) tms'\r
+  in let tms' = List.map dummize tms'\r
+  (* in let bullet = ">" / "&bullet;" *)\r
+  (* in let progress s = print_endline (bullet ^^ fancy_of_string s) *)\r
+  in let progress = print_h1\r
+  in let _ = progress "traduzione completata"\r
+  (* in let _ = List.map print_term tms' *)\r
+  in let _ = progress "ordino i sottotermini"\r
+  in let subs = List.concat (List.map subterms tms')\r
+  in let subs = stupid_sort_uniq subs\r
+  (* metti gli zeri in testa, perche' vanno calcolati per primi *)\r
+  in let zeros = mk_zeros k\r
+  in let subs = (List.filter (fun t -> not (List.mem t zeros)) subs) @ (List.rev zeros)\r
+  in let _ = progress ("sottotermini generati: " ^ string_of_int (List.length subs))\r
+  in let vars = vars subs\r
+  (* in let _ = List.iter print_term subs *)\r
+  (* in let _ = 0/0 *)\r
+  in let fv = List.filter (function Tvar(_, None, _) as v -> v <> dummy | _ -> false) vars\r
+  (* in let _ = print_string ("> free vars: " ^ String.concat ", " (List.map (string_of_term) fv)) *)\r
+  in let _ = progress "sto creando i match"\r
+  (* in let sigma = List.map (fun x -> x, crea_match k subs x) fv *)\r
+  in let f t acc = let res = crea_match k subs acc t in (t,res)::acc\r
+  in let acc = List.fold_right f subs []\r
+  in let sigma = List.filter (fun (t,res) -> List.mem t fv) acc\r
+  in let _ = progress "match creati"\r
+  in let _ = List.iter (fun (x,y) -> print_endline (fancy_of_term x ^^ (" : " / " &#8614; ") ^^ fancy_of_nf y)) sigma\r
+\r
+  in let _ = progress "controllo di purezza";\r
+  in let open Lambda3\r
+  in let ps, _ = Lambda3.parse' strings\r
+  in let ps = List.map (fun x -> Lambda3.mk_app x (`Var 1010)) ps\r
+  in let ps = List.map (fun t -> ToScott.t_of_nf (t :> nf)) ps\r
+  in let sigma = List.map (\r
+    function (Tvar(n,_,_), inst) -> n, ToScott.t_of_nf inst | _ -> assert false\r
+    ) sigma\r
+  in let ps =\r
+    List.fold_left (fun ps (x,inst) -> List.map (Pure.subst false x inst) ps) ps sigma\r
+  in let _ = List.iteri (fun i n ->\r
+    (* print_string_endline ((string_of_int i) ^ ":: " ^ (Pure.print (Pure.whd n))); *)\r
+    (* assert (Pure.whd n = Scott.mk_n (Lambda3.index_of (List.nth tms' i) subs))) ps *)\r
+    assert (is_scott_n (Pure.whd n) (Lambda3.index_of (List.nth tms' i) subs))) ps\r
+  in let _ = progress "fatto." in ()\r
+);;\r
+\r
+let do_everything tms =\r
+let tms' = parse tms in\r
+let k = compute_special_k tms' in\r
+let h = compute_special_h tms' in\r
+(* let _ = print_string_endline (string_of_int h) in *)\r
+magic tms k h\r
+;;\r
+\r
+let _ =\r
+  let tms = ["a a"; "a b"; "b a"; "b (x. y.x y a)"] in\r
+  (* 1 2 *)\r
+  (* let tms = ["x c" ; "b (x c d e)"; "b"] in *)\r
+  (* 0 1 *)\r
+  (* let tms = ["x x x"] in *)\r
+  let tms' = parse tms in\r
+  let k = compute_special_k tms' in\r
+  let h = compute_special_h tms' in\r
+  (* let _ = print_string_endline (string_of_int h) in *)\r
+  magic tms k h\r
+;;\r
+\r
+(* type var' = (* unique name *) int * (int * term') option * (*dead*) bool option\r
+and term' =\r
+  | Tvar' of var'\r
+  | Tapp' of term' * term' * (* active *) bool\r
+  | Tlam' of int * term'\r
+;;\r
+\r
+let rec iter mustapply =\r
+  let aux = function\r
+  | Tvar'(n, Some(m,t), b) -> Tvar(n, Some(m, aux t), b)\r
+  | Tvar' _ as v -> v\r
+  | Tapp'(t1, t2, b) -> if b &&\r
+  in aux\r
+;; *)\r
+\r
+*)\r
index 34c078854eaaec370ed157e88ba320dff38adbbd..38346b0ff7622135c1d3b59cd8673bf0c654bfa9 100644 (file)
@@ -16,10 +16,11 @@ type t =
 \r
 \r
 type problem = {\r
-   freshno : int\r
- ; div : t\r
+   orig_freshno: int\r
+ ; freshno : int\r
+ ; div : t list\r
  ; conv : t list\r
- ; matches : (var (* variable originating this match *) * (t (* term to discriminate *) * t (* continuation *)) list) list\r
+ ; matches : (var (* variable originating this match *) * (bool (* term comes from div*) * (t (* term to discriminate *) * t (* continuation *))) list) list\r
  ; sigma : (var * t) list (* substitutions *)\r
 }\r
 \r
@@ -35,19 +36,40 @@ let string_of_t p =
  in aux 0\r
 ;;\r
 \r
+let string_of_t p =\r
+  let bound_vars = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"] in\r
+  let rec string_of_term_w_pars level = function\r
+    | V v -> if v >= level then "`" ^ string_of_int (v-level) else List.nth bound_vars (level - v-1)\r
+    | A _ as t -> "(" ^ string_of_term_no_pars_app level t ^ ")"\r
+    | L _ as t -> "(" ^ string_of_term_no_pars_lam level t ^ ")"\r
+    | LM (ts,liftno,id) -> "[match orig="^ string_of_term_w_pars 0 (V id)^"]"\r
+    | B -> "BOT"\r
+    | P -> "PAC"\r
+  and string_of_term_no_pars_app level = function\r
+    | A(t1,t2) -> (string_of_term_no_pars_app level t1) ^ " " ^ (string_of_term_w_pars level t2)\r
+    | _ as t -> string_of_term_w_pars level t\r
+  and string_of_term_no_pars_lam level = function\r
+    | L t -> "λ" ^ string_of_term_w_pars (level+1) (V 0) ^ ". " ^ (string_of_term_no_pars_lam (level+1) t)\r
+    | _ as t -> string_of_term_no_pars level t\r
+  and string_of_term_no_pars level = function\r
+    | L _ as t -> string_of_term_no_pars_lam level t\r
+    | _ as t -> string_of_term_no_pars_app level t\r
+  in string_of_term_no_pars 0\r
+;;\r
+\r
 let string_of_problem p =\r
  let lines = [\r
-  "[DV] " ^ string_of_t p p.div;\r
+  "[DV] " ^ String.concat "\n     " (List.map (string_of_t p) p.div);\r
   "[CV] " ^ String.concat "\n     " (List.map (string_of_t p) p.conv);\r
-  "" ;\r
- ] @ Util.concat_map (fun (_, lst) -> "[<>]" :: List.map (fun (t,c) -> "     " ^ string_of_t p t\r
+  (* "" ; *)\r
+ ] @ Util.concat_map (fun (v, lst) -> ("[<>] of "^(string_of_t p (V v))) :: List.map (fun (b,(t,c)) -> "   " ^ (if b then "*" else " ") ^ " " ^ string_of_t p t\r
  (* ^" -> " ^ string_of_t p c *)\r
  ) lst) p.matches @ [""] in\r
  String.concat "\n" lines\r
 ;;\r
 \r
 let problem_fail p reason =\r
- print_endline " FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL";\r
+ print_endline "!!!!!!!!!!!!!!! FAIL !!!!!!!!!!!!!!!";\r
  print_endline (string_of_problem p);\r
  failwith reason\r
 ;;\r
@@ -62,10 +84,10 @@ let add_to_match p id entry =
    List.map (fun (id',lst as x) -> if id <> id' then x else (id, entry::lst) ) p.matches\r
   with\r
   | Not_found -> (id,[entry]) :: p.matches in\r
- {p with matches=matches}\r
+ {p with matches}\r
 ;;\r
 \r
-let free_in v =\r
+let var_occurs_in v =\r
  let rec aux level = function\r
  | V v' -> v + level = v'\r
  | A(t1,t2) -> (aux level t1) || (aux level t2)\r
@@ -79,73 +101,78 @@ let free_in v =
 let rec is_inert =\r
  function\r
  | A(t,_) -> is_inert t\r
- | L _ | LM _ | B -> false\r
- | _ -> true\r
+ | V _ -> true\r
+ | L _ | LM _ | B | P -> false\r
 ;;\r
 \r
 let is_var = function V _ -> true | _ -> false;;\r
 let is_lambda = function L _ -> true | _ -> false;;\r
 let is_pacman = function P -> true | _ -> false;;\r
 \r
-let rec subst level delift sub p =\r
+let rec subst isdiv level delift sub p =\r
  function\r
  | V v -> p, if v = level + fst sub then lift level (snd sub) else V (if delift && v > level then v-1 else v)\r
- | L t -> let p, t = subst (level + 1) delift sub p t in p, L t\r
+ | L t -> let p, t = subst isdiv (level + 1) delift sub p t in p, L t\r
  | A (t1,t2) ->\r
-  let p, t1 = subst level delift sub p t1 in\r
-  let p, t2 = subst level delift sub p t2 in\r
+  let p, t1 = subst isdiv level delift sub p t1 in\r
+  let p, t2 = subst isdiv level delift sub p t2 in\r
   if t1 = B || t2 = B then p, B else\r
-  if level = 0 then mk_app p t1 t2 else p, A (t1, t2)\r
+  if level = 0 then mk_app isdiv p t1 t2 else p, A (t1, t2)\r
  | LM (ts, liftno, id) ->\r
    let p, ts =\r
     let rec aux p = function\r
     | [] -> p, []\r
     | t::ts ->\r
      let p, ts = aux p ts in\r
-     let p, t = subst (level+1) delift sub p t in\r
+     let p, t = subst isdiv (level+1) delift sub p t in\r
      p, t::ts in\r
     aux p ts in\r
    p, LM(ts, liftno, id)\r
  | B -> p, B\r
  | P -> p, P\r
-and mk_app p t1 t2 = let t1 = if t1 = P then L P else t1 in match t1 with\r
+and mk_app isdiv p t1 t2 = let t1 = if t1 = P then L P else t1 in match t1 with\r
  | L t1 ->\r
-  let p = if is_inert t2 && not (is_var t2) && free_in 0 t1 then {p with conv=t2::p.conv} else p in\r
-   subst 0 true (0, t2) p t1\r
+ (* FIXME BUG HERE! *)\r
+  if is_inert t2 && (match t2 with V v -> v > p.orig_freshno | _ -> true ) && not (var_occurs_in 0 t1)\r
+   then (if isdiv then {p with div=p.div @ [t2]} else {p with conv=p.conv @ [t2]}), lift (-1) t1\r
+   else subst isdiv 0 true (0, t2) p t1\r
  | LM(ts,liftno,id) ->\r
-  let p, t = mk_apps p t2 (List.map (lift ~-1) ts) in\r
+  let p, t = mk_apps isdiv p t2 (List.map (lift ~-1) ts) in\r
   if t = B\r
    then p, B\r
    else\r
     let p, cont = freshvar p in\r
     let newvar = V cont in\r
-    let p = add_to_match p id (t,newvar) in\r
+    let p = add_to_match p id (isdiv,(t,newvar)) in\r
       p, newvar\r
  | B\r
  | _ when t2 = B -> p, B\r
  | t1 -> p, A (t1, t2)\r
-and mk_apps p t =\r
+and mk_apps isdiv p t =\r
  function\r
  | [] -> p, t\r
- | t'::ts -> let p, t = mk_app p t t' in mk_apps p t ts\r
-and lift n = function\r
- | V m -> V (m + n)\r
- | L t -> L (lift n t)\r
- | A (t1, t2) -> A (lift n t1, lift n t2)\r
- | LM (ts, liftno, id) -> LM (List.map (lift n) ts, n + liftno, id)\r
- | B -> B\r
- | P -> P\r
+ | t'::ts -> let p, t = mk_app isdiv p t t' in mk_apps isdiv p t ts\r
+ and lift n =\r
+  let rec aux n' =\r
+   function\r
+   | V m -> V (if m >= n' then m + n else m)\r
+   | L t -> L (aux (n'+1) t)\r
+   | A (t1, t2) -> A (aux n' t1, aux n' t2)\r
+   | LM (ts, liftno, id) -> LM (List.map (aux (n'+1)) ts, n + liftno, id)\r
+   | B -> B\r
+   | P -> P\r
+  in aux 0\r
  ;;\r
 \r
-let subst = subst 0 false;;\r
+let subst isdiv = subst isdiv 0 false;;\r
 \r
 let mk_lambda t = L (lift 1 t) ;;\r
 \r
-let subst_many sub =\r
+let subst_many sub =\r
  let rec aux p = function\r
  | [] -> p, []\r
  | t::tms ->\r
-  let p, t = subst sub p t in\r
+  let p, t = subst sub p t in\r
   let p, tms = aux p tms in\r
   p, t :: tms\r
  in aux\r
@@ -156,8 +183,10 @@ let rec subst_in_matches sub p =
  | [] -> p, []\r
  | (v, branches) :: ms->\r
   let a, b = List.split branches in\r
-  let p, a = subst_many sub p a in\r
-  let p, b = subst_many sub p b in\r
+  let b, c = List.split b in\r
+  let p, b = subst_many false sub p b in\r
+  let p, c = subst_many false sub p c in\r
+  let b = List.combine b c in\r
   let branches = List.combine a b in\r
   let p, ms = subst_in_matches sub p ms in\r
   p, (v, branches) :: ms\r
@@ -165,11 +194,14 @@ let rec subst_in_matches sub p =
 \r
 let subst_in_problem (sub: var * t) (p: problem) =\r
 (* print_endline ("SUBST IN PROBLEM: " ^ string_of_t p (V (fst sub)) ^ " " ^ string_of_t p (snd sub)); *)\r
- let p', div = subst sub p p.div in\r
- let p = {p' with conv=p.conv} in\r
- let p, conv = subst_many sub p p.conv in\r
+ let div, conv = p.div, p.conv in\r
+ let p = {p with div=[]; conv=[]} in\r
+ let p, div' = subst_many true sub p div in\r
+ let p, conv' = subst_many false sub p conv in\r
  let p, matches = subst_in_matches sub p p.matches in\r
- {p with div=div; conv=conv; matches=matches; sigma=sub::p.sigma}\r
+ let p = {p with div=div'@p.div; conv=conv'@p.conv; matches} in\r
+ (* print_endline ("after sub: \n" ^ string_of_problem p); *)\r
+ {p with sigma=sub::p.sigma}\r
 ;;\r
 \r
 (* FIXME *)\r
@@ -182,14 +214,14 @@ let rec unify p =
  let rec give_duplicates =\r
   let rec aux' t = function\r
   | [] -> [], None\r
-  | (t',c')::ts -> if t = t' then ts, Some c' else (\r
-   let ts, res = aux' t ts in (t',c')::ts, res) in\r
+  | (b',(t',c'))::ts -> if t = t' (* FIXME! eta-eq here *)then ts, Some (b',c') else (\r
+   let ts, res = aux' t ts in (b',(t',c'))::ts, res) in\r
   let rec aux = function\r
    | [] -> [], None\r
-   | (t,c)::rest -> (\r
+   | (b,(t,c))::rest -> (\r
     match aux' t rest with\r
     | rest, None -> aux rest\r
-    | rest, Some c' -> (t,c)::rest, Some (c', c)\r
+    | rest, Some (b',c') -> ((if not b' then false else b),(t,c))::rest, Some (c', c)\r
     ) in\r
   function\r
   | [] -> [], None\r
@@ -207,72 +239,120 @@ let rec unify p =
 ;;\r
 \r
 let problem_done p =\r
-  let all_separated = List.for_all (fun (_, lst) -> List.length lst = 1 || List.for_all (fun (t,_) -> is_var t) lst) p.matches in\r
-  all_separated && p.div = B\r
+  let all_separated = List.for_all (fun (_, lst) -> List.length lst = 1 || List.for_all (fun (_,(t,_)) -> is_var t) lst) p.matches in\r
+  all_separated && List.exists ((=) B) p.div\r
+;;\r
+\r
+let free_vars p t =\r
+ let rec aux level = function\r
+ | V v -> if v >= level then [v] else []\r
+ | A(t1,t2) -> (aux level t1) @ (aux level t2)\r
+ | L t -> aux (level+1) t\r
+ | LM(ts,_,id) -> (List.concat (List.map (aux level) ts)) @ (\r
+  let lst = List.assoc id p.matches in\r
+  List.concat (List.map (fun (_,(t1,t2)) -> (aux 0 t1) @ (aux 0 t2)) lst)\r
+ )\r
+ | B -> []\r
+ | P -> []\r
+ in Util.sort_uniq (aux 0 t)\r
+;;\r
+\r
+let visible_vars p t =\r
+ let rec aux = function\r
+ | V v -> [v]\r
+ | A(t1,t2) -> (aux t1) @ (aux t2)\r
+ | L t -> []\r
+ | LM(ts,_,id) -> (List.concat (List.map aux ts)) @ (\r
+  let lst = List.assoc id p.matches in\r
+  List.concat (List.map (fun (_,(t1,t2)) -> (aux t1) @ (aux t2)) lst)\r
+ )\r
+ | B -> []\r
+ | P -> []\r
+ in Util.sort_uniq (aux t)\r
+;;\r
+\r
+let forget_variable var p =\r
+ let p', div = subst_many true (var, P) p p.div in\r
+ let p = {p' with conv=p.conv} in\r
+ let p, conv = subst_many false (var, B) p p.conv in\r
+ let p, matches = subst_in_matches (var, B) p p.matches in\r
+ {p with div; conv; matches; sigma=p.sigma}\r
+;;\r
+let rec remove_divergent_discriminators p =\r
+ let f = fun (b,(t,_)) -> b && (t = B || is_lambda t) in\r
+ try\r
+  let v,l = List.find (fun (_,lst) -> List.exists f lst) p.matches in\r
+  let (_,(_,c)) as entry = List.find f l in\r
+  let l = List.filter ((<>) entry) l in\r
+  let matches = List.map (fun (v', l') -> v', if v' = v then l else l') p.matches in\r
+  let vars = free_vars p c in\r
+  let p = {p with matches} in\r
+  List.fold_right forget_variable vars p\r
+ with Not_found -> p\r
 ;;\r
 \r
 exception Done;;\r
 \r
 let sanity p =\r
+ (* try to fix divergent discriminators *)\r
+ let p = remove_divergent_discriminators p in\r
+ (* Remove lambdas from conv TODO remove duplicates *)\r
+ let div = List.filter (function | P | L _ -> false | _ -> true) p.div in\r
+ let conv = List.filter (function | B | V _ | A _ -> true | _ -> false) p.conv in\r
+ let p = {p with div;conv} in\r
  (* Sanity checks: *)\r
- if is_lambda p.div || is_pacman p.div then problem_fail p "p.div converged" ;\r
List.iter (function | B -> problem_fail p "p.conv diverged" | _ -> ()) p.conv;\r
- if not (List.for_all (fun (_, lst) -> List.for_all (fun (t,_) -> is_inert t) lst) p.matches)\r
-  then problem_fail p "Lambda in a match: k was not big enough?";\r
+ if p.div = [] then problem_fail p "p.div converged";\r
if List.mem B p.conv then problem_fail p "p.conv diverged";\r
+ if not (List.for_all (fun (_, lst) -> List.for_all (fun (b,(t,_)) -> is_inert t) lst) p.matches)\r
+  then problem_fail p "Unsolvable discrimination";\r
 \r
- (* Remove lambdas from conv TODO remove duplicates *)\r
- let conv = List.filter is_inert p.conv in\r
- let p = {p with conv=conv} in\r
  (* unify! :( *)\r
  let p = unify p in\r
- print_endline (string_of_problem p);\r
+ print_endline (string_of_problem p); (* non cancellare *)\r
  if problem_done p then raise Done else p\r
 ;;\r
 \r
+let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);;\r
+\r
 let ignore var n p =\r
-print_endline (\r
- "--- EAT on " ^ string_of_t p (V var)\r
- ^ " (of:" ^ string_of_int n ^ ")");\r
+ print_cmd "EAT" ("on " ^ string_of_t p (V var) ^ " (of:" ^ string_of_int n ^ ")");\r
  let rec aux m t =\r
   if m = 0\r
    then lift n t\r
    else L (aux (m-1) t) in\r
- let subst = var, aux n (V var) in\r
+ let p, fresh = freshvar p in\r
+ let subst = var, aux n (V fresh) in\r
  sanity (subst_in_problem subst p)\r
 ;;\r
 \r
-let explode' var p =\r
- print_endline (\r
- "--- EXPLODE on " ^ string_of_t p (V var)\r
- );\r
- let subst = var, B in\r
- sanity (subst_in_problem subst p)\r
- ;;\r
-\r
 let explode p =\r
- match p.div with\r
- | V var -> explode' var p\r
+ let fv1 = List.concat (List.map (visible_vars p) p.div) in\r
+ let fv2 = List.concat (List.map (visible_vars p) p.conv) in\r
+ let fv = List.filter (fun x -> not (List.mem x fv2)) fv1 in\r
+ let fv = List.filter ((<) p.orig_freshno) fv in\r
+ match fv with\r
+ | var::_ ->\r
+  print_cmd "EXPLODE" ("on " ^ string_of_t p (V var));\r
+  let subst = var, B in\r
+  sanity (subst_in_problem subst p)\r
  | _ -> problem_fail p "premature explosion"\r
 ;;\r
 \r
 let step var p =\r
- print_endline (\r
-  "--- STEP on " ^ string_of_t p (V var));\r
+ print_cmd "STEP" ("on " ^ string_of_t p (V var));\r
  let subst = var, LM([], 0, var) in\r
  sanity (subst_in_problem subst p)\r
 ;;\r
 \r
 let id var p =\r
- print_endline (\r
-  "--- ID on " ^ string_of_t p (V var));\r
+ print_cmd "ID" ("on " ^ string_of_t p (V var));\r
  let subst = var, L(V 0) in\r
  sanity (subst_in_problem subst p)\r
 ;;\r
 \r
 let apply var appk p =\r
- print_endline (\r
-  "--- APPLY_CONSTS on " ^ string_of_t p (V var)\r
-  ^ " (special_k:" ^ string_of_int appk ^ ")");\r
+ print_cmd "APPLY"\r
+  (string_of_t p (V var) ^ " applies no." ^ string_of_int appk ^ " fresh variables");\r
  let rec mk_freshvars n p =\r
   if n = 0\r
    then p, []\r
@@ -281,23 +361,21 @@ let apply var appk p =
     let p, v = freshvar p in\r
     p, V(v)::vs in\r
  let p, vars = mk_freshvars appk p in\r
- let p, t = mk_apps p (V 0) (List.map (lift 1) vars) in\r
+ let p, t = mk_apps false p (V 0) (List.map (lift 1) vars) in\r
  let t = L (A (lift 1 (V var), t))  in\r
  let subst = var, t in\r
  sanity (subst_in_problem subst p)\r
 ;;\r
 \r
 let perm var n p =\r
- print_endline (\r
-  "--- PERM on " ^ string_of_t p (V var)\r
-  ^ " (of:" ^ string_of_int n ^ ")");\r
- (* let p, v = freshvar p in *)\r
+ print_cmd "PERM" ("on " ^ string_of_t p (V var) ^ " (of:" ^ string_of_int n ^ ")");\r
+ let p, v = freshvar p in\r
  let rec aux' m t = if m < 0 then t else A(aux' (m-1) t, V m) in\r
  let rec aux m t =\r
   if m = 0\r
    then aux' (n-1) t\r
    else L (aux (m-1) t) in\r
- let t = aux n (lift n (V var)) in\r
+ let t = aux n (lift n (V v)) in\r
  let subst = var, t in\r
  sanity (subst_in_problem subst p)\r
 ;;\r
@@ -307,33 +385,51 @@ let perm var n p =
   allo stesso modo e' possibile ignorare dei rami se vanno in variabili, e quelle variabili\r
   vengono sostituite ovunque: con bombe in conv e con pacman in div\r
 *)\r
-(* let forget var n p =\r
- let remove_from_branch p var n = ... in\r
- let p, (tm, c) = remove_from_branch p var n in\r
- print_endline (\r
-  "--- FORGET " ^ string_of_t p tm ^ " from the match of " ^ string_of_t p (V var)\r
-  ^ " (of:" ^ string_of_int n ^ ")");\r
- sanity p\r
-;; *)\r
+let forget var no p =\r
+ try\r
+  let l = List.assoc var p.matches in\r
+  let (b,(tm,c)) = List.nth l no in\r
+  let l = List.mapi (fun n x -> if n = no then (b,(B,c)) else x) l in\r
+  let matches = List.map (fun (v,lst) -> v, if v = var then l else lst) p.matches in\r
+  let p = {p with matches} in\r
+  print_cmd "FORGET" (string_of_t p tm ^ " from the match of " ^ string_of_t p (V var));\r
+  sanity p\r
+  (* (match c with\r
+   | V var ->\r
+   print_endline (\r
+    "--- FORGET " ^ string_of_t p tm ^ " from the match of " ^ string_of_t p (V var));\r
+   let p = forget_variable var p in\r
+\r
+   | _ -> print_endline "too late to forget that term"; p\r
+  ) *)\r
+ with Failure "nth" ->\r
+  print_endline "wtf?"; p\r
+;;\r
 \r
 let parse strs =\r
- let dummy_p = {freshno=0; div=V 0; conv=[]; matches=[]; sigma=[]} in\r
+ let dummy_p = {orig_freshno=0; freshno=0; div=[]; conv=[]; matches=[]; sigma=[]} in\r
   let rec aux level = function\r
   | Parser.Lam t -> L (aux (level + 1) t)\r
   | Parser.App (t1, t2) ->\r
-   if level = 0 then snd (mk_app dummy_p (aux level t1) (aux level t2))\r
+   if level = 0 then snd (mk_app false dummy_p (aux level t1) (aux level t2))\r
     else A(aux level t1, aux level t2)\r
   | Parser.Var v -> V v\r
   in let (tms, free) = Parser.parse_many strs\r
   in (List.map (aux 0) tms, free)\r
 ;;\r
 \r
+let rec list_split n =\r
+ function\r
+ | [] -> [], []\r
+ | x::xs as l -> if n = 0 then [], l else let a, b = list_split (n-1) xs in x::a, b\r
+;;\r
+\r
 let magic6 div conv cmds =\r
  print_hline ();\r
- let all_tms, var_names = parse (div :: conv) in\r
- let div, conv = List.hd all_tms, List.tl all_tms in\r
- let freshno = 1 + List.length var_names in\r
- let p = {freshno; div; conv; matches=[]; sigma=[]} in\r
+ let all_tms, var_names = parse (div @ conv) in\r
+ let div, conv = list_split (List.length div) all_tms in\r
+ let varno = List.length var_names in\r
+ let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]} in\r
  let p = try\r
   let subst = Util.index_of "BOMB" var_names, L B in\r
   let p = subst_in_problem subst p in p\r
@@ -347,14 +443,22 @@ let magic6 div conv cmds =
 \r
 let interactive div conv cmds =\r
  print_hline ();\r
- let all_tms, var_names = parse (div :: conv) in\r
- let div, conv = List.hd all_tms, List.tl all_tms in\r
- let freshno = 1 + List.length var_names in\r
- let p = {freshno; div; conv; matches=[]; sigma=[]} in\r
+ let all_tms, var_names = parse (div @ conv) in\r
+ let div, conv = list_split (List.length div) all_tms in\r
+ let varno = List.length var_names in\r
+ let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]} in\r
+ (* activate bombs *)\r
  let p = try\r
   let subst = Util.index_of "BOMB" var_names, L B in\r
-  let p = subst_in_problem subst p in p\r
+   subst_in_problem subst p\r
+  with Not_found -> p in\r
+ (* activate pacmans *)\r
+ let p = try\r
+  let subst = Util.index_of "PACMAN" var_names, P in\r
+   let p = subst_in_problem subst p in\r
+   (print_endline ("after subst in problem " ^ string_of_problem p); p)\r
   with Not_found -> p in\r
+ (* initial sanity check *)\r
  let p = sanity p in\r
  let p = List.fold_left (|>) p cmds in\r
  let rec f p cmds =\r
@@ -368,37 +472,38 @@ let interactive div conv cmds =
     else if uno = "step" then step (nth spl 1)\r
     else if uno = "perm" then perm (nth spl 1) (nth spl 2)\r
     else if uno = "apply" then apply (nth spl 1) (nth spl 2)\r
+    else if uno = "forget" then forget (nth spl 1) (nth spl 2)\r
     else if uno = "id" then id (nth spl 1)\r
-    else failwith "unknown"\r
-    with Failure _ -> print_endline "Wrong input."; (fun x -> x) in\r
+    else failwith "Wrong input."\r
+    with Failure s -> print_endline s; (fun x -> x) in\r
   let str, cmd = read_cmd () in\r
-  let cmds = str::cmds in\r
+  let cmds = (" " ^ str ^ ";")::cmds in\r
   try\r
    let p = cmd p in f p cmds\r
   with\r
-  | Done -> List.iter print_endline (List.rev cmds)\r
+  | Done -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds)\r
  in f p []\r
 ;;\r
 \r
 let _ = magic6\r
- "x x"\r
+ ["x x"]\r
  [ "_. BOMB" ]\r
  [ ignore 1 1; explode ]\r
 ;;\r
 \r
  let _ = magic6\r
-    "x y BOMB b"\r
+  ["x y BOMB b"]\r
   [ "x BOMB y c" ]\r
-  [ perm 1 3; step 1 ; ignore 8 2; explode; ];;\r
+  [ perm 1 3; step ; explode; ];;\r
 \r
 let _ = magic6\r
-   "x BOMB a1 c"\r
+ ["x BOMB a1 c"]\r
  [ "x y BOMB d"; "x BOMB a2 c" ]\r
- [ perm 1 3 ; step 1 ; step 12; ignore 13 1; explode; ]\r
+ [ perm 1 3 ; step 10 ; step 13; explode; ]\r
 ;;\r
 \r
 let _ = magic6\r
- "x (x x)"\r
+ ["x (x x)"]\r
  [ "x x" ; "x x x" ] [\r
  apply 1 1;\r
  step 1;\r
@@ -407,44 +512,56 @@ let _ = magic6
 ];;\r
 \r
 let _ = magic6\r
- "x (_.BOMB)"\r
+ ["x (_.BOMB)"]\r
  [ "x (_._. BOMB)" ]\r
  [ apply 1 2; ]\r
 ;;\r
 \r
 let _ = magic6\r
- "x (_.y)"\r
+ ["x (_.y)"]\r
  [ "y (_. x)" ]\r
  [ apply 1 1; ignore 1 1;  explode; ]\r
 ;;\r
 \r
 let _ = magic6\r
- "y (x a1 BOMB c) (x BOMB b1 d)"\r
+ ["y (x a1 BOMB c) (x BOMB b1 d)"]\r
  [ "y (x a2 BOMB c) (x BOMB b1 d)";\r
- "y (x a1 BOMB c) (x BOMB b2 d)";]\r
- [ perm 2 3; step 2; step 17; perm 16 2; step 16; ignore 19 1; ignore 20 1; ignore 22 1; ignore 23 1; step 1; step 26; explode; ]\r
+ "y (x a1 BOMB c) (x BOMB b2 d)";] [\r
+ perm 2 3;\r
+ step 12;\r
+ perm 17 2;\r
+ step 19;\r
+ step 18;\r
+ ignore 22 1;\r
+ ignore 21 1;\r
+ ignore 24 1;\r
+ ignore 25 1;\r
+ step 1;\r
+ step 32;\r
+ explode;\r
+ ]\r
 ;;\r
 \r
 let _ = magic6\r
- "z (y x)"\r
+ ["z (y x)"]\r
  [ "z (y (x.x))"; "y (_. BOMB)" ]\r
- [ apply 2 1; step 3; explode' 8; ]\r
+ [ apply 2 1; step 3; explode; ]\r
 ;;\r
 \r
 let _ = magic6\r
- "y x"\r
+ ["y x"]\r
  [ "y (x.x)"; "x (_. BOMB)" ]\r
  [ apply 1 1; ignore 2 1; step 1; explode; ]\r
 ;;\r
 \r
 let _ = magic6\r
- "z (y x)"\r
+ ["z (y x)"]\r
  [ "z (y (x.x))"; "y (_. BOMB)" ]\r
  [ step 1; explode; apply 2 1; id 2; ignore 3 1; ]\r
 ;;\r
 \r
 let _ = magic6\r
- "y (x a)"\r
+ ["y (x a)"]\r
  [ "y (x b)"; "x BOMB" ] [\r
  id 2;\r
  step 1;\r
@@ -452,23 +569,47 @@ let _ = magic6
 ];;\r
 \r
 magic6\r
"y (x a)" [ "y (x b)"; "x BOMB"; "y a" ]\r
["y (x a)"] [ "y (x b)"; "x BOMB"; "y a" ]\r
  [\r
  apply 1 1;\r
  perm 2 2;\r
- perm 2 2;\r
- step 3;\r
- apply 2 1;\r
- ignore 4 1;\r
- step 2;\r
- ignore 12 1;\r
- ignore 13 1;\r
- step 1;\r
+ ignore 9 1;\r
+ step 10;\r
  explode;\r
+ ];;\r
+(* "y (a c)"\r
+[ "y (b c)"; "y (x a)"; "y (x b)"; "x BOMB" ]  *)\r
+\r
+magic6\r
+["x a (x (a.y BOMB))"]\r
+[ "x b"; "x (y c)"; "x (y d)" ]\r
+[apply 1 1;\r
+apply 2 1;\r
+explode;]\r
+(* [\r
+step 1;\r
+step 3;\r
+explode' 10;\r
+(* ma si puo' fare anche senza forget *) *)\r
+(* ] *)\r
+;;\r
+\r
+(* dipendente dalla codifica? no, ma si risolve solo con id *)\r
+magic6\r
+ ["y a"] ["y b"; "x (y (_.BOMB))"]\r
+[\r
+apply 1 1;\r
+apply 2 1;\r
+explode;\r
 ];;\r
+ (* [id 1; explode];; *)\r
 \r
-interactive\r
-  "y (x a)"\r
-[ "y (x b)"; "x BOMB"; "y a" ] [];;\r
+magic6\r
+ ["PACMAN (x x x)"] ["PACMAN (x x)"]\r
+ [\r
+ ignore 2 2;\r
+ explode;\r
+ ];;\r
 \r
+print_hline();\r
 print_endline "ALL DONE. "\r
diff --git a/ocaml/andrea7.ml b/ocaml/andrea7.ml
new file mode 100644 (file)
index 0000000..4a27c79
--- /dev/null
@@ -0,0 +1,751 @@
+let (++) f g x = f (g x);;\r
+\r
+let print_hline = Console.print_hline;;\r
+\r
+type var = int;;\r
+type t =\r
+ | V of var\r
+ | A of t * t\r
+ | L of t\r
+ | B (* bottom *)\r
+ | P (* pacman *)\r
+ | Stuck of var * int\r
+ (* | Ptr of int *)\r
+;;\r
+\r
+let rec consts = (* const_apps, const_lambda *)\r
+ let rec aux1 = function\r
+ | A(t, _) -> 1 + aux1 t\r
+ | _ -> 0 in\r
+ let rec aux2 = function\r
+ | L t -> 1 + aux2 t\r
+ | _ -> 0 in\r
+ function\r
+ | A(t1, t2) as t ->\r
+    let a1, b1 = consts t1 in\r
+    let a2, b2 = consts t2 in\r
+    max (aux1 t) (max a1 a2), max b1 b2\r
+ | L t' as t ->\r
+    let a, b = consts t' in\r
+    a, max (aux2 t) b\r
+ | _ -> 0, 0\r
+;;\r
+\r
+\r
+type problem = {\r
+   orig_freshno: int\r
+ ; freshno : int\r
+ ; div : t\r
+ ; conv : t list\r
+ ; matches : (var (* variable originating this match *) * ((int (* index of the term to discriminate *) * var option (* continuation *))) list) list\r
+ ; sigma : (var * t) list (* substitutions *)\r
+ ; stepped : var list\r
+ ; arities : (var * int) list\r
+ ; k_app : int\r
+ ; k_lam : int\r
+}\r
+\r
+let dummy_p = {orig_freshno=0; freshno=0; div=B; conv=[]; matches=[]; sigma=[]; stepped=[]; arities=[]; k_app=0;k_lam=0};;\r
+\r
+let append_conv p t = let len = List.length p.conv in let p = {p with conv=t::p.conv} in p, len;;\r
+let get_conv p n = List.nth p.conv (List.length p.conv - 1 - n);;\r
+let index_of_conv t conv = List.length conv - 1 - (Util.index_of t conv);;\r
+\r
+let eq_conv = (=);;\r
+let eq_conv_indices p i j = eq_conv (get_conv p i) (get_conv p j);;\r
+let all_terms p = p.div :: p.conv;;\r
+\r
+exception Done of (var * t) list (* substitution *);;\r
+exception Fail of int * string;;\r
+\r
+let string_of_t p =\r
+  let bound_vars = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"; "x3"; "x4"; "x5"] in\r
+  let rec string_of_term_w_pars level = function\r
+    | V v -> if v >= level then "`" ^ string_of_int (v-level) else List.nth bound_vars (level - v-1)\r
+    | A _\r
+    | L _ as t -> "(" ^ string_of_term_no_pars_lam level t ^ ")"\r
+    | B -> "BOT"\r
+    | P -> "PAC"\r
+    | Stuck _ as t -> "(" ^ string_of_term_no_pars_app level t ^ ")"\r
+    (* | Ptr _ as t-> "(" ^ string_of_term_no_pars_app level t ^ ")" *)\r
+    (* "&" ^ string_of_int n *)\r
+  and string_of_term_no_pars_app level = function\r
+    | A(t1,t2) -> (string_of_term_no_pars_app level t1) ^ " " ^ (string_of_term_w_pars level t2)\r
+    | Stuck(v,n) -> ":" ^ string_of_term_no_pars_app level (V v) ^ " " ^ (string_of_term_w_pars level (get_conv p n))\r
+    (* | Ptr n -> string_of_term_no_pars_app level (get_conv p n) *)\r
+    (* | Ptr n -> "&" ^ string_of_int n *)\r
+    | _ as t -> string_of_term_w_pars level t\r
+  and string_of_term_no_pars_lam level = function\r
+    | L t -> "λ" ^ string_of_term_w_pars (level+1) (V 0) ^ ". " ^ (string_of_term_no_pars_lam (level+1) t)\r
+    | _ as t -> string_of_term_no_pars level t\r
+  and string_of_term_no_pars level = function\r
+    | L _ as t -> string_of_term_no_pars_lam level t\r
+    | _ as t -> string_of_term_no_pars_app level t\r
+  in string_of_term_no_pars 0\r
+;;\r
+\r
+let string_of_problem p =\r
+ let lines = [\r
+  "[arities] " ^ String.concat " " (List.map (fun (v,n) -> "`" ^ string_of_int v ^ "=" ^ string_of_int n) p.arities);\r
+  "[stepped]" ^ String.concat " " (List.map string_of_int p.stepped);\r
+  "[DV] " ^ (string_of_t p p.div);\r
+  "[CV] " ^ String.concat "\n     " (List.map (string_of_t p) p.conv);\r
+  (* "" ; *)\r
+ ] @ Util.concat_map (fun (v, lst) -> ("[<>] of "^(string_of_t p (V v))) :: List.map (fun (n,c) -> "   " ^ string_of_t p (get_conv p n)\r
+ ^ (match c with None -> "" | Some v -> " -> " ^ string_of_t p (V v))\r
+ ) lst) p.matches @ [""] in\r
+ String.concat "\n" lines\r
+;;\r
+\r
+let problem_fail p reason =\r
+ print_endline "!!!!!!!!!!!!!!! FAIL !!!!!!!!!!!!!!!";\r
+ print_endline (string_of_problem p);\r
+ raise (Fail (-1, reason))\r
+;;\r
+\r
+let freshvar ({freshno} as p) =\r
+ {p with freshno=freshno+1}, freshno+1\r
+;;\r
+\r
+let add_to_match p id t =\r
+ let p, entry =\r
+  try\r
+   p, index_of_conv t p.conv\r
+  with\r
+  | Not_found -> append_conv p t in\r
+ let entry' = entry, None in\r
+ let matches =\r
+  List.map (fun (id',lst as x) -> if id <> id' then x else (id, entry'::lst)) p.matches\r
+  in\r
+ {p with matches}, entry\r
+;;\r
+\r
+let var_occurs_in p v =\r
+ let rec aux level = function\r
+ | V v' -> v + level = v'\r
+ | Stuck(v',n) -> assert (v <> v'); aux level (get_conv p n)\r
+ | A(t1,t2) -> (aux level t1) || (aux level t2)\r
+ | L t -> aux (level+1) t\r
+ | B -> false\r
+ | P -> false\r
+ (* | Ptr n -> aux level (get_conv p n) *)\r
+\r
+ in aux 0\r
+;;\r
+\r
+let rec is_inert p =\r
+ function\r
+ | A(t,_) -> is_inert p t\r
+ (* | Ptr n -> is_inert p (get_conv p n) *)\r
+ | V _ | Stuck _ -> true\r
+ | L _ | B | P -> false\r
+;;\r
+\r
+let is_var = function V _ -> true | _ -> false;;\r
+let is_lambda = function L _ -> true | _ -> false;;\r
+let is_pacman = function P -> true | _ -> false;;\r
+\r
+let rec subst level delift sub p =\r
+ function\r
+ | V v -> p, if v = level + fst sub then lift level (snd sub) else V (if delift && v > level then v-1 else v)\r
+ | L t -> let p, t = subst (level + 1) delift sub p t in p, L t\r
+ | A (t1,t2) ->\r
+  let p, t1 = subst level delift sub p t1 in\r
+  let p, t2 = subst level delift sub p t2 in\r
+  if t1 = B || t2 = B then p, B else\r
+  if level = 0 then mk_app p t1 t2 else p, A (t1, t2)\r
+ | B -> p, B\r
+ | P -> p, P\r
+ (* | Ptr _ as t -> p, t *)\r
+ | Stuck(v,_) as t ->
+    assert (v <> level + fst sub); (* can't instantiate v twice after a step *)\r
+    (* FIXME!!!! URGENT!!! *)\r
+    p, t\r
+and mk_app p t1 t2 = let t1 = if t1 = P then L P else t1 in match t1 with\r
+ | L t1 -> subst 0 true (0, t2) p t1\r
+ | V v when List.mem v p.stepped ->\r
+    let p, n = add_to_match p v t2 in\r
+    p, Stuck(v, n)\r
+ | B | _ when t2 = B -> p, B\r
+ | t1 -> p, A (t1, t2)\r
+and mk_apps p t =\r
+ function\r
+ | [] -> p, t\r
+ | t'::ts -> let p, t = mk_app p t t' in mk_apps p t ts\r
+and lift n =\r
+ let rec aux n' =\r
+  function\r
+  | V m -> V (if m >= n' then m + n else m)\r
+  | L t -> L (aux (n'+1) t)\r
+  | A (t1, t2) -> A (aux n' t1, aux n' t2)\r
+  | B -> B\r
+  | P -> P\r
+  | Stuck(m,ptr) -> assert (m >= n'); Stuck(m + n, ptr)\r
+  (* | Ptr _ as t -> t *)\r
+ in aux 0\r
+;;\r
+\r
+let subst = subst 0 false;;\r
+\r
+let mk_lambda t = L (lift 1 t) ;;\r
+\r
+let subst_many sub =\r
+ let rec aux p = function\r
+ | [] -> p, []\r
+ | t::tms ->\r
+  let p, tms = aux p tms in\r
+  let p, t = subst sub p t in\r
+  p, t :: tms\r
+ in aux\r
+;;\r
+\r
+let subst_in_problem (sub: var * t) (p: problem) =\r
+(* print_endline ("SUBST IN PROBLEM: " ^ string_of_t p (V (fst sub)) ^ " |-> " ^ string_of_t p (snd sub)); *)\r
+(* BUG QUI FIXME!!!! *)\r
+ let rec mix l1 l2 = match l1, l2 with\r
+ | [], l2 -> l2\r
+ | x::xs, _::ys -> x:: (mix xs ys)\r
+ | _ -> assert false in\r
+ let p, conv = subst_many sub p p.conv in\r
+ let p, div = subst sub p p.div in\r
+ let conv = List.rev (mix (List.rev conv) (List.rev p.conv)) in\r
+ let p = {p with div; conv} in\r
+ (* print_endline ("after sub: \n" ^ string_of_problem p); *)\r
+ {p with sigma=sub::p.sigma}\r
+;;\r
+\r
+let problem_done p =\r
+  let all_separated = List.for_all (fun (_, lst) -> List.for_all (fun (n,_) -> is_var (get_conv p n)) lst) p.matches in\r
+  all_separated && p.div = B\r
+;;\r
+\r
+let free_vars p t =\r
+ let rec aux level = function\r
+ | V v -> if v >= level then [v] else []\r
+ | A(t1,t2) -> (aux level t1) @ (aux level t2)\r
+ | L t -> aux (level+1) t\r
+ | B | P\r
+ | Stuck _ -> []\r
+ (* | Ptr n -> aux 0 (get_conv p n) *)\r
+ in Util.sort_uniq (aux 0 t)\r
+;;\r
+\r
+let visible_vars p t =\r
+ let rec aux = function\r
+ | V v -> [v]\r
+ | A(t1,t2) -> (aux t1) @ (aux t2)\r
+ | B | P\r
+ | Stuck _ | L _ -> []\r
+ (* | Ptr n -> aux (get_conv p n) *)\r
+ in Util.sort_uniq (aux t)\r
+;;\r
+\r
+(* TODO FIXME *)\r
+let apply_substs p t = t;;\r
+\r
+let unblock var index cont p =\r
+ let rec aux p = function\r
+ | Stuck(v',n') as t -> p, (if var = v' && index = n' then apply_substs p (V cont) else t)\r
+ | A (t1, t2) ->\r
+    let p, t1 = aux p t1 in\r
+    let p, t2 = aux p t2 in\r
+    mk_app p t1 t2\r
+ | _ as t -> p, t in\r
+ let p, div = aux p p.div in\r
+ let _, conv = List.fold_right (fun c (p, conv) -> let p, c = aux p c in p, c::conv) p.conv (p,[]) in\r
+ {p with div; conv}\r
+;;\r
+\r
+let rec unblock_all p =\r
+ let aux (orig, m) (matches, news, p) =\r
+  let nn = List.filter (fun (n,c) -> is_var (get_conv p n) && c = None) m in\r
+  let p, conts = List.fold_left (fun (p,conts) (n,_) ->\r
+    match Util.find_opt (function (n', c) when eq_conv_indices p n' n -> c | _ -> None) m\r
+    with Some c -> p, (n, c)::conts | None ->\r
+     (* c is the new continuation *)\r
+     let p, c = freshvar p in\r
+     let arity = c, List.assoc orig p.arities - 1 in\r
+     print_endline ("``" ^ string_of_int orig);\r
+     assert ((snd arity) > -1 );\r
+     let p = {p with arities=arity::p.arities} in\r
+     p, (n, c)::conts\r
+   ) (p, []) nn in\r
+  let m = List.map (fun (n,c) -> n, try\r
+   Some (List.assoc n conts)\r
+  with\r
+  | Not_found -> c) m in\r
+  (orig, m) :: matches, (List.map (fun x -> orig, x) conts) @ news, p\r
+ in\r
+ let matches, news, p = List.fold_right aux p.matches ([],[], p) in\r
+ (* FIXPOINT *)\r
+ if news <> [] then\r
+ let f = List.fold_left (fun f (a,(b,c)) -> f ++ (unblock a b c)) (fun p -> p) news in\r
+ unblock_all (f {p with matches}) else p\r
+;;\r
+\r
+let rec simple_explode p =\r
+ match p.div with\r
+ | V var ->\r
+  let subst = var, B in\r
+  sanity (subst_in_problem subst p)\r
+ | _ -> p\r
+\r
+and sanity p =\r
+ (* Sanity checks: *)\r
+ if (function | P | L _ -> true | _ -> false) p.div then problem_fail p "p.div converged";\r
+ if List.mem B p.conv then problem_fail p "p.conv diverged";\r
+ if not (List.for_all (fun (_, lst) -> List.for_all (fun (n,_) -> is_inert p (get_conv p n)) lst) p.matches)\r
+  then problem_fail p "Unsolvable discrimination";\r
+\r
+ let p = unblock_all p in\r
+ print_endline (string_of_problem p); (* non cancellare *)\r
+ let p = if problem_done p then raise (Done p.sigma) else p in\r
+ let p = if is_var p.div then simple_explode p else p in\r
+ p\r
+;;\r
+\r
+let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);;\r
+\r
+let rec hd_args t = match t with\r
+ | V v -> v, []\r
+ | A(t1,t2) -> let a, b = hd_args t1 in a, b @ [t2]\r
+ | _ -> -666, []\r
+;;\r
+\r
+let max_arity_of_var v =\r
+ let rec aux level =\r
+ function\r
+ | V _ -> 0\r
+ | A _ as t -> print_string (string_of_t dummy_p t); let hd, args = hd_args t in\r
+    let acc = if hd = level + v then List.length args else 0 in\r
+    List.fold_right (max ++ (aux level)) args acc\r
+ | L t -> aux (level + 1) t\r
+ | Stuck(v,n) -> 0\r
+ (* | Ptr n -> assert false *)\r
+ | P | B -> 0\r
+ in aux 0\r
+;;\r
+\r
+let ignore var n p =\r
+ print_cmd "EAT" ("on " ^ string_of_t p (V var) ^ " (of:" ^ string_of_int n ^ ")");\r
+ let rec aux m t =\r
+  if m = 0\r
+   then lift n t\r
+   else L (aux (m-1) t) in\r
+ let p, fresh = freshvar p in\r
+ let subst = var, aux n (V fresh) in\r
+ sanity (subst_in_problem subst p)\r
+;;\r
+\r
+\r
+\r
+let eat var p =\r
+ print_cmd "EAT" ("var " ^ string_of_t p (V var));\r
+ let rec is_hd v' = function\r
+ | A (t,_) -> is_hd v' t\r
+ | V v -> v' = v\r
+ | _ -> false in\r
+ let rec app_length = function\r
+ | A (t,_) -> 1 + app_length t\r
+ | _ -> 0 in\r
+ let rec find_app_no = function\r
+ | V _ | L _ | P | B -> 0\r
+ | A (t1,t2) as t ->\r
+    max (max (find_app_no t1) (find_app_no t2))\r
+     (if is_hd var t1 then app_length t else 0)\r
+ | Stuck _ -> 0\r
+ (* | Ptr n -> find_app_no (get_conv p n) *)\r
+ in let n = List.fold_right (max ++ find_app_no) (all_terms p) 0 in\r
+ let rec aux m t =\r
+  if m = 0\r
+   then lift n t\r
+   else L (aux (m-1) t) in\r
+ let p, fresh = freshvar p in\r
+ let subst = var, aux n (V fresh) in\r
+ sanity (subst_in_problem subst p)\r
+;;\r
+\r
+(* let explode p =\r
+ let fv1 = visible_vars p p.div in\r
+ let fv2 = List.concat (List.map (visible_vars p) p.conv) in\r
+ let fv = List.filter (fun x -> not (List.mem x fv2)) fv1 in\r
+ let fv = List.filter ((<) p.orig_freshno) fv in\r
+ match fv with\r
+ | var::_ ->\r
+  print_cmd "EXPLODE" ("on " ^ string_of_t p (V var));\r
+  let subst = var, B in\r
+  sanity (subst_in_problem subst p)\r
+ | _ -> raise (Fail (-1,"premature explosion"))\r
+;; *)\r
+\r
+(* let step var p =
+ print_cmd "STEP" ("on " ^ string_of_t p (V var));
+ let matches = (var,[])::p.matches in
+ let p = {p with matches;stepped=var::p.stepped} in
+ let subst = var, V var in
+ sanity (subst_in_problem subst p)\r
+;; *)\r
+\r
+let choose n p =\r
+ print_cmd "CHOOSE" ("#" ^ string_of_int n);\r
+ let rec aux n t = match t with\r
+ | V _ -> 0, t\r
+ | A(t1,_) -> let n', t' = aux n t1 in if n = n' then n', t' else n'+1, t\r
+ | _ -> assert false\r
+ in let n', div = aux n p.div in\r
+ if n' <> n then problem_fail p "wrong choose";\r
+ let p = {p with div} in\r
+ sanity p\r
+;;\r
+\r
+let apply var appk p =\r
+ print_cmd "APPLY"\r
+  (string_of_t p (V var) ^ " applies no." ^ string_of_int appk ^ " fresh variables");\r
+ let rec mk_freshvars n p =\r
+  if n = 0\r
+   then p, []\r
+   else\r
+    let p, vs = mk_freshvars (n-1) p in\r
+    let p, v = freshvar p in\r
+    p, V(v)::vs in\r
+ let p, vars = mk_freshvars appk p in\r
+ let p, t = mk_apps p (V 0) (List.map (lift 1) vars) in\r
+ let t = L (A (lift 1 (V var), t))  in\r
+ let subst = var, t in\r
+ sanity (subst_in_problem subst p)\r
+;;\r
+\r
+let find_arities_after_app p =\r
+ let rec aux level n = function\r
+ | L t -> assert (n > 0); max_arity_of_var level t :: aux (level+1) (n-1) t\r
+ | _ -> Array.to_list (Array.make n 0)\r
+ in aux 0\r
+;;\r
+let find_all_first_args_of v =\r
+ let rec aux level = function\r
+ | L t -> aux (level+1) t\r
+ | V _ -> []\r
+ | A(V v', t2) -> (if v + level = v' then [t2] else []) @ aux level t2\r
+ | A(t1,t2) -> aux level t1 @ aux level t2\r
+ | _ -> []\r
+ in aux 0\r
+;;\r
+\r
+let step' var p =\r
+ let appk = p.k_lam + p.k_app + 1 in\r
+ print_cmd "STEP'" ("on " ^ string_of_t p (V var) ^ " and applies no." ^ string_of_int appk ^ " fresh variables");\r
+ let p, vars = (* +1 below because of lifting *)\r
+  Array.fold_left (fun (p,vars) _ -> let p, v = freshvar p in p, (v+1)::vars)\r
+   (p, []) (Array.make appk ()) in\r
+ let p, t = mk_apps p (V 0) (List.map (fun x -> V x) vars) in\r
+\r
+ let first_args = Util.sort_uniq (List.fold_right ((@) ++ (find_all_first_args_of var)) (all_terms p) []) in\r
+ let map = List.fold_left (fun acc t -> let acc' = find_arities_after_app p appk t in List.map (fun (x,y) -> max x y) (List.combine acc acc')) (Array.to_list (Array.make appk 0)) first_args in\r
+ let arities = List.combine (List.map ((+) (-1)) vars) map in\r
+\r
+ (* let p, var' = freshvar p in *)\r
+ let p, var' = p, var in\r
+ let matches = (var', []) :: p.matches in\r
+ let p = {p with matches; stepped=var'::p.stepped; arities=arities@p.arities} in\r
+ let t = L (A (lift 1 (V var'), t))  in\r
+ let subst = var, t in\r
+ sanity (subst_in_problem subst p)\r
+;;\r
+\r
+let perm var n p =\r
+ if n = 1 then p else (\r
+ print_cmd "PERM" ("on " ^ string_of_t p (V var) ^ " (of:" ^ string_of_int n ^ ")");\r
+ (* let p, v = freshvar p in *)\r
+ let p, v = p, var in\r
+ let rec aux' m t = if m < 0 then t else A(aux' (m-1) t, V m) in\r
+ let rec aux m t =\r
+  if m = 0\r
+   then aux' (n-1) t\r
+   else L (aux (m-1) t) in\r
+ let t = aux n (lift n (V v)) in\r
+ let subst = var, t in\r
+ (* let p = {p with arities=(v, List.assoc var p.arities)::p.arities} in *)\r
+ sanity (subst_in_problem subst p)\r
+) ;;\r
+\r
+let free_vars_of_p p =\r
+ Util.sort_uniq (Util.concat_map (free_vars p) (all_terms p));;\r
+\r
+let rec applied_vars p = function\r
+| B | P -> []\r
+| L _ -> [] (* ??? *)\r
+| V _ -> []\r
+| A(V v,t2) -> v :: applied_vars p t2\r
+| A(t1,t2) -> applied_vars p t1 @ applied_vars p t2\r
+(* | Ptr n -> applied_vars p (get_conv p n) *)\r
+| Stuck _ -> [] (* ??? *)\r
+;;\r
+\r
+let applied_vars_of_p p =\r
+ Util.sort_uniq (Util.concat_map (applied_vars p) (all_terms p));;\r
+\r
+let rec auto p =\r
+ let aux f var =\r
+  try\r
+   auto (f var); ()\r
+  with\r
+  | Done _ as d -> raise d\r
+  | Fail(_, s) -> print_endline ("<<< Backtracking because: " ^ s) in\r
+ print_endline ">>> auto called";\r
+ (* Compute useful free variables *)\r
+ let fv = applied_vars_of_p p in\r
+ let fv = List.filter (fun v -> not (List.mem v p.stepped)) fv in\r
+ List.iter (fun v -> print_string ("@`" ^ string_of_int v)) fv;\r
+ let fv0 = List.filter (fun v -> List.assoc v p.arities > 0) fv in (* remove variable with arity left 0, cannot step there *)\r
+ if fv0 = [] then (print_endline "warning! empty step fv0"; List.iter (fun v -> print_string ("@`" ^ string_of_int v)) fv);\r
+ let permute_and_step p v =\r
+  let step'' problem prm var =\r
+   let problem = perm var prm problem in\r
+   (* let _ = read_line () in *)\r
+   let problem = step' var problem in\r
+   problem in\r
+  let arity = List.assoc v p.arities in\r
+  let _, perms = Array.fold_left (fun (arity, acc) () -> let a = arity + 1 in a, a::acc) (1,[1]) (Array.make (arity-1) ()) in\r
+  List.iter (fun perm -> aux (step'' p perm) v) perms\r
+ in\r
+ List.iter (permute_and_step p) fv0;\r
+ List.iter (aux (fun v -> eat v p)) fv;\r
+ (* mancano: applicazioni e choose; ??? *)\r
+;;\r
+\r
+let parse strs =\r
+  let rec aux level = function\r
+  | Parser.Lam t -> L (aux (level + 1) t)\r
+  | Parser.App (t1, t2) ->\r
+   if level = 0 then snd (mk_app dummy_p (aux level t1) (aux level t2))\r
+    else A(aux level t1, aux level t2)\r
+  | Parser.Var v -> V v\r
+  in let (tms, free) = Parser.parse_many strs\r
+  in (List.map (aux 0) tms, free)\r
+;;\r
+\r
+let magic6 div conv cmds =\r
+ print_hline ();\r
+ let all_tms, var_names = parse (div :: conv) in\r
+ let div, conv = List.hd all_tms, List.tl all_tms in\r
+ let varno = List.length var_names in\r
+ let k_app, k_lam = List.fold_left (fun (a, b) t -> let a', b' = consts t in max a a', max b b') (0,0) all_tms in\r
+ let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]; stepped=[];k_app;k_lam;arities=[]} in\r
+ let fv = Util.sort_uniq (Util.concat_map (free_vars p) all_tms) in\r
+ let arities = List.map (fun var -> var, k_app) fv in\r
+ let p = {p with arities} in\r
+ let p = try\r
+  let subst = Util.index_of "BOMB" var_names, L B in\r
+  let p = subst_in_problem subst p in p\r
+  with Not_found -> p in\r
+ let p = sanity p in\r
+ try\r
+  problem_fail (List.fold_left (|>) p cmds) "Problem not completed"\r
+ with\r
+ | Done _ -> ()\r
+;;\r
+\r
+let auto div conv =\r
+ print_hline ();\r
+ let all_tms, var_names = parse (div :: conv) in\r
+ let div, conv = List.hd all_tms, List.tl all_tms in\r
+ let varno = List.length var_names in\r
+ let k_app, k_lam = List.fold_left (fun (a, b) t -> let a', b' = consts t in max a a', max b b') (0,0) all_tms in\r
+ let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]; stepped=[];k_app;k_lam;arities=[]} in\r
+ let fv = Util.sort_uniq (Util.concat_map (free_vars p) all_tms) in\r
+ let max_arity_of_var_in_p var p =\r
+  1 + List.fold_right (max ++ (max_arity_of_var var)) (all_terms p) 0 in\r
+ let arities = List.map (fun var -> var, max_arity_of_var_in_p var p) fv in\r
+ let p = {p with arities} in\r
+ let p = try\r
+  let subst = Util.index_of "BOMB" var_names, L B in\r
+  let p = subst_in_problem subst p in p\r
+  with Not_found -> p in\r
+ let p = sanity p in\r
+ try\r
+  auto p;\r
+  failwith "auto failed."\r
+ with\r
+ | Done _ -> print_endline "<<< auto ok >>>"; (* TODO: print and verify substitution *)\r
+;;\r
+\r
+(* let interactive div conv cmds =\r
+ print_hline ();\r
+ let all_tms, var_names = parse (div @ conv) in\r
+ let div, conv = list_split (List.length div) all_tms in\r
+ let varno = List.length var_names in\r
+ let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]} in\r
+ (* activate bombs *)\r
+ let p = try\r
+  let subst = Util.index_of "BOMB" var_names, L B in\r
+   subst_in_problem subst p\r
+  with Not_found -> p in\r
+ (* activate pacmans *)\r
+ let p = try\r
+  let subst = Util.index_of "PACMAN" var_names, P in\r
+   let p = subst_in_problem subst p in\r
+   (print_endline ("after subst in problem " ^ string_of_problem p); p)\r
+  with Not_found -> p in\r
+ (* initial sanity check *)\r
+ let p = sanity p in\r
+ let p = List.fold_left (|>) p cmds in\r
+ let rec f p cmds =\r
+  let nth spl n = int_of_string (List.nth spl n) in\r
+  let read_cmd () =\r
+   let s = read_line () in\r
+   let spl = Str.split (Str.regexp " +") s in\r
+   s, let uno = List.hd spl in\r
+    try if uno = "explode" then explode\r
+    else if uno = "ignore" then ignore (nth spl 1) (nth spl 2)\r
+    else if uno = "step" then step (nth spl 1)\r
+    else if uno = "perm" then perm (nth spl 1) (nth spl 2)\r
+    else if uno = "apply" then apply (nth spl 1) (nth spl 2)\r
+    (* else if uno = "forget" then forget (nth spl 1) (nth spl 2) *)\r
+    else if uno = "id" then id (nth spl 1)\r
+    else failwith "Wrong input."\r
+    with Failure s -> print_endline s; (fun x -> x) in\r
+  let str, cmd = read_cmd () in\r
+  let cmds = (" " ^ str ^ ";")::cmds in\r
+  try\r
+   let p = cmd p in f p cmds\r
+  with\r
+  | Done -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds)\r
+ in f p []\r
+;; *)\r
+\r
+let _ = auto\r
+ "x x"\r
+ [ "_. BOMB" ]\r
+ (* [ eat 1 ] *)\r
+;;\r
+\r
+\r
+let _ = auto\r
+   "x y BOMB b"\r
+ [ "x BOMB y c" ]\r
+ (* [ perm 1 3; step' 8 ; eat 4; eat 5; eat 15; ] *)\r
+;;\r
+\r
+\r
+let _ = auto\r
+ "x BOMB a1 c"\r
+ [ "x y BOMB d"; "x BOMB a2 c" ]\r
+ (* [ perm 1 3 ; step' 10 ; eat 4; eat 6;  step' 17; eat 3; eat 7; eat 27; ] *)\r
+;;\r
+\r
+\r
+let _ = auto\r
+ "x (x x)"\r
+ [ "x x" ; "x x x" ]\r
+ (* [\r
+ step' 1;\r
+ eat 6; eat 9; eat 13;\r
+]*)\r
+;;\r
+\r
+\r
+(* let _ = auto\r
+ "x (_.BOMB)"\r
+ [ "x (_._. BOMB)" ]\r
+ (* [ apply 1 2; ] *)\r
+;; *)\r
+\r
+\r
+let _ = auto\r
+ "x (_.y)"\r
+ [ "y (_. x)" ]\r
+ (* [ apply 1 1; ignore 1 1;  explode; ] *)\r
+;;\r
+\r
+\r
+let _ = auto\r
+ "y (x a1 BOMB c) (x BOMB b1 d)"\r
+ [ "y (x a2 BOMB c) (x BOMB b1 d)";\r
+ "y (x a1 BOMB c) (x BOMB b2 d)";]\r
+ (* [perm 2 3;\r
+ step 12;\r
+ perm 17 2;\r
+ step 19;\r
+ step 18;\r
+ ignore 22 1;\r
+ ignore 21 1;\r
+ ignore 24 1;\r
+ ignore 25 1;\r
+ step 1;\r
+ step 32;\r
+ explode;\r
+ ] *)\r
+;;\r
+\r
+(*\r
+let _ = magic6\r
+ ["z (y x)"]\r
+ [ "z (y (x.x))"; "y (_. BOMB)" ]\r
+ [ apply 2 1; step 3; explode; ]\r
+;;\r
+\r
+let _ = magic6\r
+ ["y x"]\r
+ [ "y (x.x)"; "x (_. BOMB)" ]\r
+ [ apply 1 1; ignore 2 1; step 1; explode; ]\r
+;;\r
+\r
+let _ = magic6\r
+ ["z (y x)"]\r
+ [ "z (y (x.x))"; "y (_. BOMB)" ]\r
+ [ step 1; explode; apply 2 1; id 2; ignore 3 1; ]\r
+;;\r
+\r
+let _ = magic6\r
+ ["y (x a)"]\r
+ [ "y (x b)"; "x BOMB" ] [\r
+ id 2;\r
+ step 1;\r
+ explode;\r
+];;\r
+\r
+magic6\r
+ ["y (x a)"] [ "y (x b)"; "x BOMB"; "y a" ]\r
+ [\r
+ apply 1 1;\r
+ perm 2 2;\r
+ ignore 9 1;\r
+ step 10;\r
+ explode;\r
+ ];;\r
+(* "y (a c)"\r
+[ "y (b c)"; "y (x a)"; "y (x b)"; "x BOMB" ]  *)\r
+\r
+magic6\r
+["x a (x (a.y BOMB))"]\r
+[ "x b"; "x (y c)"; "x (y d)" ]\r
+[apply 1 1;\r
+apply 2 1;\r
+explode;]\r
+(* [\r
+step 1;\r
+step 3;\r
+explode' 10;\r
+(* ma si puo' fare anche senza forget *) *)\r
+(* ] *)\r
+;;\r
+\r
+(* dipendente dalla codifica? no, ma si risolve solo con id *)\r
+magic6\r
+ ["y a"] ["y b"; "x (y (_.BOMB))"]\r
+[\r
+apply 1 1;\r
+apply 2 1;\r
+explode;\r
+];;\r
+ (* [id 1; explode];; *)\r
+\r
+magic6\r
+ ["PACMAN (x x x)"] ["PACMAN (x x)"]\r
+ [\r
+ ignore 2 2;\r
+ explode;\r
+ ];; *)\r
+\r
+print_hline();\r
+print_endline "ALL DONE. "\r
index dbd73966ad6d22c7ab9c4d8227df66d4ce581254..6b59ed9fc065fdc95678bd0103de356102ff28ee 100644 (file)
@@ -5,16 +5,24 @@ open Num
 
 let bomb = ref(`Var ~-1);;
 
+type var = int;;
+
 type problem =
  { freshno: int
  ; div: i_var option (* None = bomb *)
  ; conv: i_n_var list (* the inerts that must converge *)
  ; ps: i_n_var list (* the n-th inert must become n *)
- ; sigma: (int * nf) list (* the computed substitution *)
+ ; sigma: (var * nf) list (* the computed substitution *)
  ; deltas: (int * nf) list ref list (* collection of all branches *)
- ; steps: int (* how many steps the algorithm made until now *)
+ (* ; steps: int (* the bound on the number of steps *) *)
+ ; arities: int list
+ ; special_k: int
  }
 
+let string_of_nf {freshno} t =
+ let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
+ print ~l (t :> nf)
+;;
 
 (* let heads = Util.sort_uniq (List.map hd_of_i_var p.ps) in
 for all head
@@ -22,6 +30,7 @@ for all head
 
 (* let ($) f x = f x;; *)
 
+
 let subterms tms freshno =
  let apply_var =
   let no = ref freshno in
@@ -52,7 +61,7 @@ let all_terms p =
 ;;
 
 let problem_measure p =
- let l = Array.to_list (Array.init (p.freshno + 1) string_of_var) in
+ (* let l = Array.to_list (Array.init (p.freshno + 1) string_of_var) in *)
  let open Listx in
  (* aux |t1;t2| e' numero di step per portare la diff in testa
     INVARIANTE: t1 <eta> t2
@@ -78,7 +87,7 @@ let problem_measure p =
     (* no. di step da fare per separare t1 e t2 *)
  in let diff t1 t2 = (
   let res = if eta_eq t1 t2 then 0 else aux t1 t2 in
-  if res <> 0 then prerr_endline ("diff (" ^ print ~l t1 ^ ") (" ^ print ~l t2 ^ ") = " ^ string_of_int res);
+  (* if res <> 0 then prerr_endline ("diff (" ^ print ~l t1 ^ ") (" ^ print ~l t2 ^ ") = " ^ string_of_int res); *)
   res
   )
  (* aux calcola la somma delle differenze tra i termini in una lista (quadratico) *)
@@ -93,13 +102,223 @@ let problem_measure p =
  in a + b
 ;;
 
-let print_problem label ({freshno; div; conv; ps; deltas; steps} as p) =
+(* AC MEASURE *)
+module ACMeasure = struct
+type var = int;;
+
+type state = {
+ freshno : int;
+ arities : int list;
+ p : problem;
+}
+
+let string_of_state s =
+ "STATE\n - arities: " ^
+ String.concat " " (List.mapi (fun v n -> "`"^string_of_var v ^ "=" ^ string_of_int n) s.p.arities)
+;;
+
+let rec get_var_of_match bs p =
+ let rec aux = function
+ | (v,`Lam(_,`Match(_,_,bs',_)))::sigma -> if bs = bs' then v else aux sigma
+ | _::sigma -> aux sigma
+ | [] -> assert false
+ in aux p.sigma
+;;
+
+let mk_freshvar s =
+ let freshno = s.freshno + 1 in
+ {s with freshno}, freshno
+;;
+
+let rec mk_apps vmap (h : nf) (args : var list) =
+ let aux l = Listx.from_list (List.map (fun x -> `Var x) l) in
+ match h,args with
+  | _, [] -> vmap, h
+  | `I(n,args'), _ -> vmap, `I(n, Listx.append (aux args) args')
+  | `Var n, _ -> vmap, `I(n, aux args)
+  | `Lam(_,nf), a::args -> mk_apps (a::vmap) (lift ~-1 nf) args
+  | `Match(t,lift,bs,args'), _ -> vmap, `Match(t,lift,bs,List.append args' (Listx.to_list (aux args)))
+  | _ -> assert false
+;;
+
+let mk_freshvars s n = Array.fold_right (fun () (s,acc) -> let s, v = mk_freshvar s in s, v::acc ) (Array.make n ()) (s, [])
+;;
+
+let get_arity_of_var p v t =
+ (* prerr_endline (string_of_nf p t); *)
+ let rec aux level = function
+ | `Var _ | `N _-> 0
+ | `I(v', tms) as t ->
+    max
+     (if v + level = v' then (
+      (* prerr_endline("found applied " ^ string_of_var v ^" in "^print (lift (-level) t)); *)
+      Listx.length tms) else 0)
+     (aux_listx level tms)
+ | `Lam(_,t) -> aux (level + 1) t
+ | `Match(t, liftno, bs, args) -> max (aux level (t :> nf)) (aux_list level args)
+ and aux_listx level listx = Listx.fold_left (fun x t -> max x (aux level t)) 0 listx
+ and aux_list level lst = List.fold_left (fun x t -> max x (aux level t)) 0 lst
+ in aux 0 t
+;;
+
+(* let mk_apps t args = List.fold_left mk_app t args;; *)
+
+let first_arg = function
+ | Listx.Nil x
+ | Listx.Cons(x,_) -> x
+;;
+
+let find_first_args var =
+ let rec aux level : nf -> nf list = function
+ | `Var _ | `N _ -> []
+ | `I(v, args) -> (if var + level = v then [first_arg args] else []) @ (Util.concat_map (aux level) (Listx.to_list args))
+ | `Lam(_,t) -> aux (level+1) t
+ | `Match(t, liftno, bs, args) -> aux level (t :> nf) @ (Util.concat_map (aux level) (args))
+ in aux 0
+;;
+
+let remove_lambdas k t =
+ let rec aux = function
+ | `Lam(_,t) -> aux t
+ | _ as t -> t
+ in lift (-k) (aux t)
+;;
+
+let get_arity_of_continuation p v =
+ if !bomb = `Var v then 0 else (
+  let bs = List.find (fun bs -> List.exists (fun (_,t) -> t = `Var v) !bs) p.deltas in
+  let orig = get_var_of_match bs p in
+  List.nth p.arities orig
+ )
+;;
+
+let fix_arities p v freshvars =
+ let all_terms = (all_terms p :> nf list) in
+ let args = Util.concat_map (find_first_args v) all_terms in
+ let k = List.length freshvars in
+ let args = List.map (remove_lambdas k) args in
+ prerr_endline ("delifted lambdas in which to look for "^ string_of_var v);
+ (* List.iter (fun t -> prerr_endline(strilogng_of_nf p t)) args; *)
+ (* assert (List.length args > 0); *)
+ List.iter (fun v -> prerr_endline ("var to fix: fresh " ^ string_of_var v)) freshvars;
+ let find_arities_args v = let i = List.fold_left (fun x t -> max x (get_arity_of_var p v t)) 0 args in prerr_endline ("found arity in args of " ^ string_of_var (List.nth (List.rev freshvars) (v+1)) ^ ": " ^ string_of_int i); i in
+ (* let find_arities_all v = List.fold_left (fun x t -> max x (get_arity_of_var p v t)) 0 all_terms in *)
+ let arities = List.mapi (fun var () ->
+  if var < List.length p.arities
+   then List.nth p.arities var
+   else if List.mem var freshvars
+    then 1 + find_arities_args (Util.index_of var (List.rev freshvars) - 1)
+    (* else find_arities_all var *)
+    else (get_arity_of_continuation p var) - 1
+ ) (Array.to_list (Array.make (p.freshno+1) ())) in
+ assert (List.length arities = (p.freshno + 1));
+ (* prerr_endline ("arities added : " ^ string_of_int (List.length freshvars)); *)
+ (* List.iter (fun (v,n) -> prerr_endline(string_of_int v ^ "=" ^ string_of_int n)) arities; *)
+ {p with arities}
+;;
+
+let measure =
+ let rec aux (s:state) vmap =
+ let p = s.p in
+ let realvar vmap v =
+  (* prerr_endline ("waant " ^ string_of_int v ^ "; we have "^ string_of_int (List.length vmap)); *)
+  if v < 0 then List.nth vmap (-1-v) else v in
+ function
+ | `Var _ | `N _-> 0
+ | `I(v, tms) -> assert (List.length s.arities = (s.freshno + 1)); 1 +
+   let v = realvar vmap v in
+   (* prerr_endline ("lookup for arity of " ^ string_of_int v ^ "with freshno =" ^ string_of_int s.freshno ^ " and length = " ^ string_of_int (List.length s.arities)); *)
+   let arity = List.nth s.arities v in
+   1 + if arity = 0 then 0 else (
+    let first, rest = (match tms with
+    | Listx.Nil x -> x, []
+    | Listx.Cons(a,b) -> a, Listx.to_list b) in
+    (
+     let s, vars = mk_freshvars s (1+s.p.special_k) in
+     let vmap, t = mk_apps vmap first (vars) in
+     let arities = List.mapi (fun v () ->
+      if v < List.length s.arities
+       then List.nth s.arities v
+       else get_arity_of_var p (realvar vmap v) t
+     ) (Array.to_list (Array.make (s.freshno + 1) ())) in
+     (* let arities = (List.map (fun v -> v, get_arity_of_var p (realvar vmap' v) t) vars) in *)
+     (* let arities = arities @ s.arities in *)
+     let s = {s with arities} in
+     aux s vmap t
+    ) + (
+     let s, fresh = mk_freshvar s in
+     let arities = s.arities @ [arity - 1] in
+     let s = {s with arities} in
+     if rest = [] then aux s vmap (`Var fresh) else
+      aux s vmap (`I (fresh, Listx.from_list rest))
+    )
+   )
+  | `Match(t, _, bs, rest) ->
+     let tmp = aux s vmap (t :> nf) in
+     let s, fresh = mk_freshvar s in
+     let arity = List.nth s.arities (get_var_of_match bs s.p) in
+     let arities = s.arities @ [arity - 1] in
+     let s = {s with arities} in
+     tmp + if rest = [] then aux s vmap (`Var(fresh)) else
+      aux s vmap (`I(fresh, Listx.from_list rest))
+  | `Lam _ -> assert false
+ in fun s -> aux s []
+;;
+
+
+(* let measure p =
+ let rec m = function
+ | `N _ | `Var  _ -> 0
+ | `I(_,args) ->
+   let args = Listx.to_list args in
+   List.fold_left (fun acc t -> acc + m t) (1 + Listx.length args) args
+ | `Lam(_,t) -> m t
+ | `Match(t, lft, bs, rest) ->
+   (* let var = get_var_of_match bs p in *)
+   let args = rest in m (t :> nf) + List.fold_left (fun acc t -> acc + m t) (aux args) args
+
+and aux = function
+ | [] -> 0
+ | x::xs -> m x + if aux xs = 0 then 0 else 1 + aux xs
+in m
+;;*)
+
+let measure_many s tms = List.fold_left (fun x t -> x + (measure s t)) 0 tms;;
+
+let map_max f l = List.fold_left (fun x t -> max x (f t)) 0 l;;
+
+let measure_of_problem p =
+ let tms = (all_terms p :> nf list) in
+ let freshno = p.freshno in
+ let arities = p.arities in
+ let s = {arities; freshno; p} in
+ prerr_endline (string_of_state s);
+ let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
+ List.iter (fun t -> prerr_endline (string_of_int (measure s t) ^ " ::" ^ print ~l t)) tms;
+ let m = measure_many s tms in
+ (* prerr_endline (string_of_int m); *)
+ m
+;;
+end;;
+
+let measure_of_problem = ACMeasure.measure_of_problem;;
+let problem_measure = measure_of_problem;;
+(* AC MEASURE *)
+
+let print_problem label ({freshno; div; conv; ps; deltas} as p) =
+ (* assert (p.steps > List.length p.sigma); *)
+ let measure = try
+  problem_measure p
+ with
+ | _ -> -1 in
  Console.print_hline ();
  prerr_endline ("\n||||| Displaying problem: " ^ label ^ " |||||");
  let nl = "\n| " in
  let deltas = String.concat nl (List.map (fun r -> String.concat " <> " (List.map (fun (i,_) -> string_of_int i) !r)) deltas) in
  let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
-    nl ^ string_of_int steps ^ " steps left; measure="^string_of_int(problem_measure p)^" freshno = " ^ string_of_int freshno
+    nl ^
+    (* (string_of_int (steps - List.length p.sigma)) ^ " steps left;" ^ *)
+    "measure="^string_of_int measure ^" freshno = " ^ string_of_int freshno
  ^ nl ^ "\b> DISCRIMINATING SETS (deltas)"
  ^ nl ^ deltas ^ (if deltas = "" then "" else nl)
  ^ "\b> DIVERGENT" ^ nl
@@ -262,7 +481,7 @@ prerr_endline ("# INST: " ^ string_of_var x ^ " := " ^ print ~l inst));
  );
  let p = {p with sigma = sigma@[x,inst]} in
  let p = super_simplify p in
- prerr_endline (print_problem "instantiate" p);
+ print_endline (print_problem "instantiate" p);
  p
 ;;
 
@@ -441,13 +660,13 @@ prerr_endline ("# INST_IN_EAT: " ^ string_of_var x ^ " := " ^ print ~l inst));
     let p, bomb' = make_fresh_var p in
     (if !bomb <> `Var (-1) then
      failwithProblem p
-      ("Bomb was duplicated! It was " ^ string_of_nf !bomb ^
-       ", tried to change it to " ^ string_of_nf bomb'));
+      ("Bomb was duplicated! It was " ^ string_of_nf !bomb ^
+       ", tried to change it to " ^ string_of_nf bomb'));
     bomb := bomb';
-    prerr_endline ("Just created bomb var: " ^ string_of_nf !bomb);
+    prerr_endline ("Just created bomb var: " ^ string_of_nf !bomb);
     let x = hd_of_i_var div in
     let inst = make_lams !bomb n in
-    prerr_endline ("# INST (div): " ^ string_of_var x ^ " := " ^ string_of_nf inst);
+    prerr_endline ("# INST (div): " ^ string_of_var x ^ " := " ^ string_of_nf inst);
     let p = {p with div=None} in
     (* subst_in_problem (hd_of_i_var div) inst p in *)
      {p with sigma=p.sigma@[x,inst]} in
@@ -480,7 +699,7 @@ List.iter (fun l -> prerr_endline (String.concat " " (List.map string_of_var l))
  let old_conv = p.conv in
  let p = { p with ps; conv } in
  if l <> [] || old_conv <> conv
-  then prerr_endline (print_problem "eat" p);
+  then print_endline (print_problem "eat" p);
  if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then
   `Finished p
  else
@@ -488,26 +707,19 @@ List.iter (fun l -> prerr_endline (String.concat " " (List.map string_of_var l))
 
 let instantiate p x n =
  (if `Var x = !bomb
-   then failwithProblem p ("BOMB (" ^ string_of_nf !bomb ^ ") cannot be instantiated!"));
+   then failwithProblem p ("BOMB (" ^ string_of_nf p !bomb ^ ") cannot be instantiated!"));
+ prerr_endline ("stepping on " ^ string_of_var x);
+ (if List.nth p.arities x <= 0 then failwith "stepped on a varible of arity <= 0");
  let p,vars = make_fresh_vars p n in
- let p,zero = make_fresh_var p in
- let zero = Listx.Nil zero in
+ let p,zero' = make_fresh_var p in
+ let zero = Listx.Nil zero' in
  let args = if n = 0 then zero else Listx.append zero (Listx.from_list vars) in
  let bs = ref [] in
  let inst = `Lam(false,`Match(`I(0,Listx.map (lift 1) args),1,bs,[])) in
  let p = {p with deltas=bs::p.deltas} in
- subst_in_problem x inst p
-;;
-
-let compute_special_k tms =
-  let rec aux k (t: nf) = Pervasives.max k (match t with
-    | `Lam(b,t) -> aux (k + if b then 1 else 0) t
-    | `I(n, tms) -> Listx.max (Listx.map (aux 0) tms)
-    | `Match(t, liftno, bs, args) ->
-        List.fold_left max 0 (List.map (aux 0) ((t :> nf)::args@List.map snd !bs))
-    | `N _ -> 0
-    | `Var _ -> 0
-  ) in Listx.max (Listx.map (aux 0) tms)
+ let p = ACMeasure.fix_arities p x (List.map (function `Var x -> x | _ -> assert false) (Listx.to_list args)) in
+ let p = subst_in_problem x inst p in
+ p
 ;;
 
 let auto_instantiate (n,p) =
@@ -560,21 +772,23 @@ in*)
 
 let rec auto_eat (n,({ps} as p)) =
  prerr_endline "{{{{{{{{ Computing measure before auto_instantiate }}}}}}";
+ let p = ACMeasure.fix_arities p (-1) [] in
  let m = problem_measure p in
  let (n,p') = auto_instantiate (n,p) in
  match eat p' with
    `Finished p -> p
  | `Continue p ->
      prerr_endline "{{{{{{{{ Computing measure inafter auto_instantiate }}}}}}";
-     let delta = m - problem_measure p' in
+     let p = ACMeasure.fix_arities p (-1) [] in
+     let delta = m - problem_measure p in
      if delta <= 0 then (
-      (* failwithProblem p' *)
+      (* failwithProblem p *)
       prerr_endline
       ("Measure did not decrease (delta=" ^ string_of_int delta ^ ")"))
      else prerr_endline ("$ Measure decreased by " ^ string_of_int delta);
-     let p' = {p' with steps=(p'.steps - 1)} in
-     (if p'.steps < 0 then prerr_endline ">>>>>>>>>> STEPS ARE OVER <<<<<<<<<"
-     (*failwithProblem p' "steps are over. sorry."*) );
+     (* let p' = {p' with steps=(p'.steps - 1)} in *)
+     (* (if p'.steps < 0 then prerr_endline ">>>>>>>>>> STEPS ARE OVER <<<<<<<<<"
+     (*failwithProblem p' "steps are over. sorry."*) ); *)
      auto_eat (n,p)
 ;;
 
@@ -677,7 +891,7 @@ let main problems =
   if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then begin
    p
   end else
-   let _ = prerr_endline (print_problem "main" p) in
+   let _ = print_endline (print_problem "main" p) in
    let x,l =
     match l with
      | cmd::l -> cmd,l
@@ -702,8 +916,10 @@ let main problems =
     bomb := `Var (-1);
     let p_finale = aux p n cmds in
     let freshno,sigma = p_finale.freshno, p_finale.sigma in
-    prerr_endline ("------- <DONE> ------\n " ^ (string_of_int (p.steps - p_finale.steps)) ^ " steps of "^ (string_of_int p.steps) ^".");
-    (* prerr_endline (print_problem "Original problem" p); *)
+    prerr_endline ("------- <DONE> ------\n "
+    (* ^ (string_of_int (p.steps - (List.length p_finale.sigma))) ^ " steps of "^ (string_of_int p.steps) ^"." *)
+    );
+    (* print_endline (print_problem "Original problem" p); *)
     prerr_endline "---------------------";
     let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
     prerr_endline (" BOMB == " ^ print ~l !bomb);
@@ -717,7 +933,7 @@ let main problems =
        (* In this non-recursive version, the intermediate states may containt Matchs *)
        List.map (fun t -> let t = subst false x inst (t :> nf) in cast_to_i_num_var t) ps)
        (p.ps :> i_num_var list) sigma in
-     prerr_endline (print_problem {p with ps= List.map (function t -> cast_to_i_n_var t) ps; freshno});
+     print_endline (print_problem {p with ps= List.map (function t -> cast_to_i_n_var t) ps; freshno});
      List.iteri (fun i (n,more_args) -> assert (more_args = 0 && n = `N i)) ps ;
 *)
     prerr_endline "---------<OPT>----------";
@@ -778,21 +994,12 @@ let append_zero =
   | _ -> assert false
 ;;
 
-let bounds_on_steps all_tms =
- let rec aux = function
- | `I(k,args) -> Listx.fold_left (fun acc t -> 1 + acc + (aux t)) 0 args
- | `Var _ -> 1
- | `Lam (_, t) -> 1 + aux t
- | _ -> assert false
- in List.fold_right ((+) ++ aux) all_tms 0
-;;
 
 type t = problem * int * string list;;
 
 let magic_conv ~div ~conv ~nums cmds =
  let all_tms = (match div with None -> [] | Some div -> [div]) @ nums @ conv in
   let all_tms, var_names = parse' all_tms in
-  let steps = bounds_on_steps all_tms in
   let div, (tms, conv) = match div with
     | None -> None, list_cut (List.length nums, all_tms)
     | Some _ -> Some (List.hd all_tms), list_cut (List.length nums, List.tl all_tms) in
@@ -800,7 +1007,7 @@ let magic_conv ~div ~conv ~nums cmds =
  if match div with None -> false | Some div -> List.exists (eta_subterm div) (tms@conv)
  then (
   prerr_endline "--- TEST SKIPPED ---";
-  {freshno=0; div=None; conv=[]; ps=[]; sigma=[]; deltas=[]; steps=(-1)}, 0, []
+  {freshno=0; div=None; conv=[]; ps=[]; sigma=[]; deltas=[]; arities=[]; special_k=(-1);}, 0, []
  ) else
   let tms = sort_uniq ~compare:eta_compare tms in
   let special_k = compute_special_k (Listx.from_list all_tms) in (* compute initial special K *)
@@ -811,11 +1018,15 @@ let magic_conv ~div ~conv ~nums cmds =
 
   let ps = List.map append_zero tms in (* crea lista applicando zeri o dummies *)
   let freshno = List.length var_names in
+  let sigma = [] in
   let deltas =
    let dummy = `Var (max_int / 2) in
-    [ ref (Array.to_list (Array.init (List.length ps) (fun i -> i, dummy))) ] in
-
-  {freshno; div; conv; ps; sigma=[] ; deltas; steps}, special_k, cmds
+   [ ref (Array.to_list (Array.init (List.length ps) (fun i -> i, dummy))) ] in
+  let p = {freshno; div; conv; ps; sigma; deltas; special_k; arities=[]} in
+  let arities =
+  List.mapi (fun i () -> ACMeasure.map_max (ACMeasure.get_arity_of_var p i) ((all_terms p) :> nf list)) (Array.to_list (Array.make (freshno+1) ())) in
+  let p = {p with arities} in
+  p, special_k, cmds
 ;;
 
 let magic strings cmds = magic_conv None [] strings cmds;;
diff --git a/ocaml/lambda4b.ml b/ocaml/lambda4b.ml
new file mode 100644 (file)
index 0000000..dbd7396
--- /dev/null
@@ -0,0 +1,821 @@
+open Util
+open Util.Vars
+open Pure
+open Num
+
+let bomb = ref(`Var ~-1);;
+
+type problem =
+ { freshno: int
+ ; div: i_var option (* None = bomb *)
+ ; conv: i_n_var list (* the inerts that must converge *)
+ ; ps: i_n_var list (* the n-th inert must become n *)
+ ; sigma: (int * nf) list (* the computed substitution *)
+ ; deltas: (int * nf) list ref list (* collection of all branches *)
+ ; steps: int (* how many steps the algorithm made until now *)
+ }
+
+
+(* let heads = Util.sort_uniq (List.map hd_of_i_var p.ps) in
+for all head
+  List.map (fun (_, bs) -> List.map (fun (x,_) -> List.nth p.ps x) !bs) p.deltas *)
+
+(* let ($) f x = f x;; *)
+
+let subterms tms freshno =
+ let apply_var =
+  let no = ref freshno in
+  function t -> incr no; mk_app t (`Var !no) in
+ let applicative hd args = snd (
+    List.fold_left (fun (hd, acc) t -> let hd = mk_app hd t in hd, hd::acc) (hd, []) args) in
+ let rec aux t = match t with
+ | `Var _ -> []
+ | `I(v,ts) ->
+    (* applicative (`Var v) (Listx.to_list ts) @  *)
+     Util.concat_map aux (Listx.to_list ts) @ List.map apply_var (Listx.to_list ts)
+ | `Lam(_,t) -> aux (lift ~-1 t)
+ | `Match(u,bs_lift,bs,args) ->
+    aux (u :> nf) @
+     (* applicative (`Match(u,bs_lift,bs,[])) args @ *)
+      Util.concat_map aux args @ List.map apply_var args
+      (* @ Util.concat_map (aux ++ (lift bs_lift) ++ snd) !bs *)
+ | `N _ -> []
+ in let tms' = (* Util.sort_uniq ~compare:eta_compare*) (Util.concat_map aux tms) in
+ tms @ tms'
+ (* List.map (fun (t, v) -> match t with `N _ -> t | _ -> mk_app t v) (List.combine tms (List.mapi (fun i _ -> `Var(freshno+i)) tms)) *)
+;;
+
+let all_terms p =
+(match p.div with None -> [] | Some t -> [(t :> i_n_var)])
+@ p.conv
+@ p.ps
+;;
+
+let problem_measure p =
+ let l = Array.to_list (Array.init (p.freshno + 1) string_of_var) in
+ let open Listx in
+ (* aux |t1;t2| e' numero di step per portare la diff in testa
+    INVARIANTE: t1 <eta> t2
+ *)
+ let rec aux t1 t2 =
+  match t1, t2 with
+  | `I(v1,nfs1), `I(v2,nfs2) ->
+    if v1 <> v2
+     then 0 else 1 + find_first_diff (to_list nfs1, to_list nfs2)
+  | `Match (t1,bs_lift,bs,args), `Match (t2,bs_lift',bs',args') ->
+     if bs != bs' then 0 (* TODO *)
+      else if eta_eq (t1 :> nf) (t2 :> nf) then 1 + find_first_diff (args, args') else aux (t1 :> nf) (t2 :> nf) (* TODO *)
+  | `Match _, _
+  | _, `Match _ -> 0 (* FIXME!!! *)
+  | `Lam(_,t1), `Lam(_,t2) -> aux t1 t2
+  | _ -> 0
+ and find_first_diff = function
+  | [], [] -> assert false
+  | [], t::_
+  | t::_, [] -> 1
+  | t1::ts1, t2::ts2 ->
+    if eta_eq (t1 :> nf) (t2 :> nf) then 1 + find_first_diff (ts1, ts2) else aux t1 t2
+    (* no. di step da fare per separare t1 e t2 *)
+ in let diff t1 t2 = (
+  let res = if eta_eq t1 t2 then 0 else aux t1 t2 in
+  if res <> 0 then prerr_endline ("diff (" ^ print ~l t1 ^ ") (" ^ print ~l t2 ^ ") = " ^ string_of_int res);
+  res
+  )
+ (* aux calcola la somma delle differenze tra i termini in una lista (quadratico) *)
+ in let rec sum = function
+  | [] -> 0
+  | x::xs -> List.fold_right ((+) ++ (diff (x :> nf))) (xs :> nf list) (sum xs)
+ in let subterms = subterms ((all_terms p) :> nf list) p.freshno
+ (* let subterms = sort_uniq ~compare:eta_compare subterms in *)
+ in let a = sum subterms
+ in let b = List.fold_right (fun bs -> (+) (sum (List.map ((List.nth p.ps) ++ fst) !bs))) p.deltas 0
+ in let _ = prerr_endline ("Computed measure: " ^ string_of_int a ^ "," ^ string_of_int b)
+ in a + b
+;;
+
+let print_problem label ({freshno; div; conv; ps; deltas; steps} as p) =
+ Console.print_hline ();
+ prerr_endline ("\n||||| Displaying problem: " ^ label ^ " |||||");
+ let nl = "\n| " in
+ let deltas = String.concat nl (List.map (fun r -> String.concat " <> " (List.map (fun (i,_) -> string_of_int i) !r)) deltas) in
+ let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
+    nl ^ string_of_int steps ^ " steps left; measure="^string_of_int(problem_measure p)^" freshno = " ^ string_of_int freshno
+ ^ nl ^ "\b> DISCRIMINATING SETS (deltas)"
+ ^ nl ^ deltas ^ (if deltas = "" then "" else nl)
+ ^ "\b> DIVERGENT" ^ nl
+ ^ "*: " ^ (match div with None -> "*" | Some div -> print ~l (div :> nf)) ^ "\n| "
+ ^ "\b> CONVERGENT" ^ nl
+ ^ String.concat "\n| " (List.map (fun t -> "_: " ^ (if t = `N (-1) then "_" else print ~l (t :> nf))) conv) ^
+ (if conv = [] then "" else "\n| ")
+ ^ "\b> NUMERIC" ^ nl
+ ^ String.concat "\n| " (List.mapi (fun i t -> string_of_int i ^ ": " ^ print ~l (t :> nf)) ps)
+ ^ nl
+;;
+
+
+let failwithProblem p reason =
+ print_endline (print_problem "FAIL" p);
+ failwith reason
+;;
+
+let make_fresh_var p =
+ let freshno = p.freshno + 1 in
+ {p with freshno}, `Var freshno
+;;
+
+let make_fresh_vars p m =
+ Array.fold_left
+  (* fold_left vs. fold_right hides/shows the bug in problem q7 *)
+  (fun (p, vars) _ -> let p, var = make_fresh_var p in p, var::vars)
+  (p, [])
+  (Array.make m ())
+;;
+
+let simple_expand_match ps =
+  let rec aux level = function
+  | #i_num_var as t -> aux_i_num_var level t
+  | `Lam(b,t) -> `Lam(b, aux (level+1) t)
+  and aux_i_num_var level = function
+  | `Match(u,bs_lift,bs,args) as torig ->
+    let u = aux_i_num_var level u in
+    bs := List.map (fun (n, x) -> n, aux 0 x) !bs;
+    (try
+       (match u with
+         | #i_n_var as u ->
+            let i = index_of (lift (-level) u) (ps :> nf list) (* can raise Not_found *)
+            in let t = mk_match (`N i) bs_lift bs args in
+            if t <> torig then
+            aux level (t :> nf)
+           else raise Not_found
+         | _ -> raise Not_found)
+      with Not_found ->
+       `Match(cast_to_i_num_var u,bs_lift,bs,List.map (aux level) args))
+  | `I(k,args) -> `I(k,Listx.map (aux level) args)
+  | `N _ | `Var _ as t -> t
+in aux_i_num_var 0;;
+
+let fixpoint f =
+ let rec aux x = let x' = f x in if x <> x' then aux x' else x in aux
+;;
+
+let rec super_simplify_ps ps =
+ fixpoint (List.map (cast_to_i_num_var ++ (simple_expand_match ps)))
+;;
+
+let super_simplify ({div; ps; conv} as p) =
+  let ps = super_simplify_ps p.ps (p.ps :> i_num_var list) in
+  let conv = super_simplify_ps ps (p.conv :> i_num_var list) in
+  let div = option_map (fun div ->
+   let divs = super_simplify_ps p.ps ([div] :> i_num_var list) in
+    List.hd divs) div in
+  {p with div=option_map cast_to_i_var div; ps=List.map cast_to_i_n_var ps; conv=List.map cast_to_i_n_var conv}
+
+exception ExpandedToLambda;;
+
+let subst_in_problem x inst ({freshno; div; conv; ps; sigma} as p) =
+ let len_ps = List.length ps in
+(*(let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
+prerr_endline ("# INST0: " ^ string_of_var x ^ " := " ^ print ~l inst));*)
+ let rec aux ((freshno,acc_ps,acc_new_ps) as acc) =
+  function
+  | [] -> acc
+  | t::todo_ps ->
+(*prerr_endline ("EXPAND t:" ^ print (t :> nf));*)
+     let t = subst false x inst (t :> nf) in
+(*prerr_endline ("SUBSTITUTED t:" ^ print (t :> nf));*)
+     let freshno,new_t,acc_new_ps =
+      expand_match (freshno,acc_ps@`Var(max_int/3)::todo_ps,acc_new_ps) t
+     in
+      aux (freshno,acc_ps@[new_t],acc_new_ps) todo_ps
+
+  (* cut&paste from aux above *)
+  and aux' ps ((freshno,acc_conv,acc_new_ps) as acc) =
+   function
+   | [] -> acc
+   | t::todo_conv ->
+(*prerr_endline ("EXPAND t:" ^ print (t :> nf));*)
+      (* try *)
+       let t = subst false x inst (t :> nf) in
+(*prerr_endline ("SUBSTITUTED t:" ^ print (t :> nf));*)
+       let freshno,new_t,acc_new_ps =
+        expand_match (freshno,ps,acc_new_ps) t
+       in
+        aux' ps (freshno,acc_conv@[new_t],acc_new_ps) todo_conv
+      (* with ExpandedToLambda -> aux' ps (freshno,acc_conv@[`N(-1)],acc_new_ps) todo_conv *)
+
+  (* cut&paste from aux' above *)
+  and aux'' ps (freshno,acc_new_ps) =
+   function
+   | None -> freshno, None, acc_new_ps
+   | Some t ->
+      let t = subst false x inst (t :> nf) in
+      let freshno,new_t,acc_new_ps =
+       expand_match (freshno,ps,acc_new_ps) t
+      in
+       freshno,Some new_t,acc_new_ps
+
+  and expand_match ((freshno,acc_ps,acc_new_ps) as acc) t =
+   match t with
+   | `Match(u',bs_lift,bs,args) ->
+        let freshno,u,acc_new_ps = expand_match acc (u' :> nf) in
+        let acc_new_ps,i =
+         match u with
+         | `N i -> acc_new_ps,i
+         | _ ->
+            let ps = List.map (fun t -> cast_to_i_num_var (subst false x inst (t:> nf))) (acc_ps@acc_new_ps) in
+            let super_simplified_ps = super_simplify_ps ps ps in
+(*prerr_endline ("CERCO u:" ^ print (fst u :> nf));
+List.iter (fun x -> prerr_endline ("IN: " ^ print (fst x :> nf))) ps;
+List.iter (fun x -> prerr_endline ("IN2: " ^ print (fst x :> nf))) super_simplified_ps;*)
+            match index_of_opt ~eq:eta_eq super_simplified_ps u with
+               Some i -> acc_new_ps, i
+             | None -> acc_new_ps@[u], len_ps + List.length acc_new_ps
+        in
+         let freshno=
+          if List.exists (fun (j,_) -> i=j) !bs then
+           freshno
+          else
+           let freshno,v = freshno+1, `Var (freshno+1) in (* make_fresh_var freshno in *)
+           bs := !bs @ [i, v] ;
+           freshno in
+(*prerr_endlie ("t DA RIDURRE:" ^ print (`Match(`N i,arity,bs_lift,bs,args) :> nf) ^ " more_args=" ^ string_of_int more_args);*)
+         let t = mk_match (`N i) bs_lift bs args in
+(*prerr_endline ("NUOVO t:" ^ print (fst t :> nf) ^ " more_args=" ^ string_of_int (snd t));*)
+          expand_match (freshno,acc_ps,acc_new_ps) t
+   | `Lam _ -> raise ExpandedToLambda
+   | #i_n_var as x ->
+      let x = simple_expand_match (acc_ps@acc_new_ps) x in
+      freshno,cast_to_i_num_var x,acc_new_ps in
+
+ let freshno,old_ps,new_ps = aux (freshno,[],[]) (ps :> i_num_var list) in
+ let freshno,conv,new_ps = aux' old_ps (freshno,[],new_ps) (conv :> i_num_var list) in
+ let freshno,div,new_ps = aux'' old_ps (freshno,new_ps) (div :> i_num_var option) in
+ let div = option_map cast_to_i_var div in
+ let ps = List.map cast_to_i_n_var (old_ps @ new_ps) in
+ let conv = List.map cast_to_i_n_var conv in
+(let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
+prerr_endline ("# INST: " ^ string_of_var x ^ " := " ^ print ~l inst));
+ let p = {p with freshno; div; conv; ps} in
+ ( (* check if double substituting a variable *)
+  if List.exists (fun (x',_) -> x = x') sigma
+   then failwithProblem p "Variable replaced twice"
+ );
+ let p = {p with sigma = sigma@[x,inst]} in
+ let p = super_simplify p in
+ prerr_endline (print_problem "instantiate" p);
+ p
+;;
+
+exception Dangerous
+
+let arity_of arities k =
+ let _,pos,y = List.find (fun (v,_,_) -> v=k) arities in
+ let arity = match y with `Var _ -> 0 | `I(_,args) -> Listx.length args | _ -> assert false in
+ arity + if pos = -1 then - 1 else 0
+;;
+
+let rec dangerous arities showstoppers =
+ function
+    `N _
+  | `Var _
+  | `Lam _ -> ()
+  | `Match(t,liftno,bs,args) ->
+      (* CSC: XXX partial dependency on the encoding *)
+      (match t with
+          `N _ -> List.iter (dangerous arities showstoppers) args
+        | `Match _ as t -> dangerous arities showstoppers t ; List.iter (dangerous arities showstoppers) args
+        | `Var x -> dangerous_inert arities showstoppers x args 2 (* 2 coming from Scott's encoding *)
+        | `I(x,args') -> dangerous_inert arities showstoppers x (Listx.to_list args' @ args) 2 (* 2 coming from Scott's encoding *)
+      )
+  | `I(k,args) -> dangerous_inert arities showstoppers k (Listx.to_list args) 0
+
+and dangerous_inert arities showstoppers k args more_args =
+ List.iter (dangerous arities showstoppers) args ;
+ if List.mem k showstoppers then raise Dangerous else
+ try
+  let arity = arity_of arities k in
+  if List.length args + more_args > arity then raise Dangerous else ()
+ with
+  Not_found -> ()
+
+(* cut & paste from above *)
+let rec dangerous_conv arities showstoppers =
+ function
+    `N _
+  | `Var _
+  | `Lam _ -> []
+  | `Match(t,liftno,bs,args) ->
+      (* CSC: XXX partial dependency on the encoding *)
+      (match t with
+          `N _ -> concat_map (dangerous_conv arities showstoppers) args
+        | `Match _ as t -> dangerous_conv arities showstoppers t @ concat_map (dangerous_conv arities showstoppers) args
+        | `Var x -> dangerous_inert_conv arities showstoppers x args 2 (* 2 coming from Scott's encoding *)
+        | `I(x,args') -> dangerous_inert_conv arities showstoppers x (Listx.to_list args' @ args) 2 (* 2 coming from Scott's encoding *)
+      )
+  | `I(k,args) -> dangerous_inert_conv arities showstoppers k (Listx.to_list args) 0
+
+and dangerous_inert_conv arities showstoppers k args more_args =
+ concat_map (dangerous_conv arities showstoppers) args @
+ if List.mem k showstoppers then k :: concat_map free_vars args else
+ try
+  let arity = arity_of arities k in
+  prerr_endline ("dangerous_inert_conv: ar=" ^ string_of_int arity ^ " k="^string_of_var k ^ " listlenargs=" ^ (string_of_int (List.length args)) );
+  if List.length args + more_args > arity then k :: concat_map free_vars args else []
+ with
+  Not_found -> []
+
+(* inefficient algorithm *)
+let rec edible arities div ps conv showstoppers =
+ let rec aux showstoppers =
+  function
+     [] -> showstoppers
+   | x::xs when List.exists (fun y -> hd_of x = Some y) showstoppers ->
+      (* se la testa di x e' uno show-stopper *)
+      let new_showstoppers = sort_uniq (showstoppers @ free_vars (x :> nf)) in
+      (* aggiungi tutte le variabili libere di x *)
+      if List.length showstoppers <> List.length new_showstoppers then
+       aux new_showstoppers ps
+      else
+       aux showstoppers xs
+   | x::xs ->
+      match hd_of x with
+         None -> aux showstoppers xs
+       | Some h ->
+          try
+           dangerous arities showstoppers (x : i_n_var :> nf) ;
+           aux showstoppers xs
+          with
+           Dangerous ->
+            aux (sort_uniq (h::showstoppers)) ps
+  in
+    let showstoppers = sort_uniq (aux showstoppers ps) in
+    let dangerous_conv =
+     List.map (dangerous_conv arities showstoppers) (conv :> nf list) in
+
+    prerr_endline ("dangerous_conv lenght:" ^ string_of_int (List.length dangerous_conv));
+    List.iter (fun l -> prerr_endline (String.concat " " (List.map string_of_var l))) dangerous_conv;
+    let showstoppers' = showstoppers @ List.concat dangerous_conv in
+    let showstoppers' = sort_uniq (match div with
+     | None -> showstoppers'
+     | Some div ->
+       if List.exists ((=) (hd_of_i_var div)) showstoppers'
+       then showstoppers' @ free_vars (div :> nf) else showstoppers') in
+    if showstoppers <> showstoppers' then edible arities div ps conv showstoppers' else showstoppers', dangerous_conv
+;;
+
+let precompute_edible_data {ps; div} xs =
+ (match div with None -> [] | Some div -> [hd_of_i_var div, -1, (div :> i_n_var)]) @
+  List.map (fun hd ->
+   let i, tm = Util.findi (fun y -> hd_of y = Some hd) ps in
+    hd, i, tm
+   ) xs
+;;
+
+let critical_showstoppers p =
+  let p = super_simplify p in
+  let hd_of_div = match p.div with None -> [] | Some t -> [hd_of_i_var t] in
+  let showstoppers_step =
+  concat_map (fun bs ->
+    let heads = List.map (fun (i,_) -> List.nth p.ps i) !bs in
+    let heads = List.sort compare (hd_of_div @ filter_map hd_of heads) in
+    snd (split_duplicates heads)
+    ) p.deltas @
+     if List.exists (fun t -> [hd_of t] = List.map (fun x -> Some x) hd_of_div) p.conv
+     then hd_of_div else [] in
+  let showstoppers_step = sort_uniq showstoppers_step in
+  let showstoppers_eat =
+   let heads_and_arities =
+    List.sort (fun (k,_) (h,_) -> compare k h)
+     (filter_map (function `Var k -> Some (k,0) | `I(k,args) -> Some (k,Listx.length args) | _ -> None ) p.ps) in
+   let rec multiple_arities =
+    function
+       []
+     | [_] -> []
+     | (x,i)::(y,j)::tl when x = y && i <> j ->
+         x::multiple_arities tl
+     | _::tl -> multiple_arities tl in
+   multiple_arities heads_and_arities in
+
+  let showstoppers_eat = sort_uniq showstoppers_eat in
+  let showstoppers_eat = List.filter
+    (fun x -> not (List.mem x showstoppers_step))
+    showstoppers_eat in
+  List.iter (fun v -> prerr_endline ("DANGEROUS STEP: " ^ string_of_var v)) showstoppers_step;
+  List.iter (fun v -> prerr_endline ("DANGEROUS EAT: " ^ string_of_var v)) showstoppers_eat;
+  p, showstoppers_step, showstoppers_eat
+  ;;
+
+let eat p =
+  let ({ps} as p), showstoppers_step, showstoppers_eat = critical_showstoppers p in
+  let showstoppers = showstoppers_step @ showstoppers_eat in
+  let heads = List.sort compare (filter_map hd_of ps) in
+  let arities = precompute_edible_data p (uniq heads) in
+  let showstoppers, showstoppers_conv =
+   edible arities p.div ps p.conv showstoppers in
+  let l = List.filter (fun (x,_,_) -> not (List.mem x showstoppers)) arities in
+  let p =
+  List.fold_left (fun p (x,pos,(xx : i_n_var)) -> if pos = -1 then p else
+   let n = match xx with `I(_,args) -> Listx.length args | _ -> 0 in
+   let v = `N(pos) in
+   let inst = make_lams v n in
+(let l = Array.to_list (Array.init (p.freshno + 1) string_of_var) in
+prerr_endline ("# INST_IN_EAT: " ^ string_of_var x ^ " := " ^ print ~l inst));
+   { p with sigma = p.sigma @ [x,inst] }
+   ) p l in
+  (* to avoid applied numbers in safe positions that
+     trigger assert failures subst_in_problem x inst p*)
+ let ps =
+  List.map (fun t ->
+   try
+    let _,j,_ = List.find (fun (h,_,_) -> hd_of t = Some h) l in
+    `N j
+   with Not_found -> t
+  ) ps in
+ let p = match p.div with
+  | None -> p
+  | Some div ->
+   if List.mem (hd_of_i_var div) showstoppers
+   then p
+   else
+    let n = match div with `I(_,args) -> Listx.length args | `Var _ -> 0 in
+    let p, bomb' = make_fresh_var p in
+    (if !bomb <> `Var (-1) then
+     failwithProblem p
+      ("Bomb was duplicated! It was " ^ string_of_nf !bomb ^
+       ", tried to change it to " ^ string_of_nf bomb'));
+    bomb := bomb';
+    prerr_endline ("Just created bomb var: " ^ string_of_nf !bomb);
+    let x = hd_of_i_var div in
+    let inst = make_lams !bomb n in
+    prerr_endline ("# INST (div): " ^ string_of_var x ^ " := " ^ string_of_nf inst);
+    let p = {p with div=None} in
+    (* subst_in_problem (hd_of_i_var div) inst p in *)
+     {p with sigma=p.sigma@[x,inst]} in
+     let dangerous_conv = showstoppers_conv in
+let _ = prerr_endline ("dangerous_conv lenght:" ^ string_of_int (List.length dangerous_conv));
+List.iter (fun l -> prerr_endline (String.concat " " (List.map string_of_var l))) dangerous_conv; in
+ let conv =
+   List.map (function s,t ->
+    try
+     if s <> [] then t else (
+     (match t with | `Var _ -> raise Not_found | _ -> ());
+     let _ = List.find (fun h -> hd_of t = Some h) showstoppers in
+      t)
+    with Not_found -> match hd_of t with
+     | None -> assert (t = `N ~-1); t
+     | Some h ->
+      prerr_endline ("FREEZING " ^ string_of_var h);
+      `N ~-1 (* convergent dummy*)
+   ) (List.combine showstoppers_conv p.conv) in
+ List.iter
+  (fun bs ->
+    bs :=
+     List.map
+      (fun (n,t as res) ->
+        match List.nth ps n with
+           `N m -> m,t
+         | _ -> res
+      ) !bs
+  ) p.deltas ;
+ let old_conv = p.conv in
+ let p = { p with ps; conv } in
+ if l <> [] || old_conv <> conv
+  then prerr_endline (print_problem "eat" p);
+ if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then
+  `Finished p
+ else
+  `Continue p
+
+let instantiate p x n =
+ (if `Var x = !bomb
+   then failwithProblem p ("BOMB (" ^ string_of_nf !bomb ^ ") cannot be instantiated!"));
+ let p,vars = make_fresh_vars p n in
+ let p,zero = make_fresh_var p in
+ let zero = Listx.Nil zero in
+ let args = if n = 0 then zero else Listx.append zero (Listx.from_list vars) in
+ let bs = ref [] in
+ let inst = `Lam(false,`Match(`I(0,Listx.map (lift 1) args),1,bs,[])) in
+ let p = {p with deltas=bs::p.deltas} in
+ subst_in_problem x inst p
+;;
+
+let compute_special_k tms =
+  let rec aux k (t: nf) = Pervasives.max k (match t with
+    | `Lam(b,t) -> aux (k + if b then 1 else 0) t
+    | `I(n, tms) -> Listx.max (Listx.map (aux 0) tms)
+    | `Match(t, liftno, bs, args) ->
+        List.fold_left max 0 (List.map (aux 0) ((t :> nf)::args@List.map snd !bs))
+    | `N _ -> 0
+    | `Var _ -> 0
+  ) in Listx.max (Listx.map (aux 0) tms)
+;;
+
+let auto_instantiate (n,p) =
+  let p, showstoppers_step, showstoppers_eat = critical_showstoppers p in
+ let x =
+  match showstoppers_step, showstoppers_eat with
+    | [], y::_ ->
+      prerr_endline ("INSTANTIATING CRITICAL TO EAT " ^ string_of_var y); y
+    | [], [] ->
+     let heads = List.sort compare (filter_map (fun t -> match t with `Var _ -> None | x -> hd_of x) ((match p.div with Some t -> [(t :> i_n_var)] | _ -> []) @ p.ps)) in
+     (match heads with
+         [] -> assert false
+       | x::_ ->
+          prerr_endline ("INSTANTIATING TO EAT " ^ string_of_var x);
+          x)
+  | x::_, _ ->
+      prerr_endline ("INSTANTIATING " ^ string_of_var x);
+      x in
+(* Strategy that decreases the special_k to 0 first (round robin)
+1:11m42 2:14m5 3:11m16s 4:14m46s 5:12m7s 6:6m31s *)
+let x =
+ try
+  match hd_of (List.find (fun t -> compute_special_k (Listx.Nil (t :> nf)) > 0) (all_terms p)) with
+      None -> assert false
+    | Some x ->
+       prerr_endline ("INSTANTIATING AND HOPING " ^ string_of_var x);
+       x
+ with
+  Not_found -> x
+in
+(* Instantiate in decreasing order of compute_special_k
+1:15m14s 2:13m14s 3:4m55s 4:4m43s 5:4m34s 6:6m28s 7:3m31s
+let x =
+ try
+  (match hd_of (snd (List.hd (List.sort (fun c1 c2 -> - compare (fst c1) (fst c2)) (filter_map (function `I _ as t -> Some (compute_special_k (Listx.Nil (t :> nf)),t) | _ -> None) (all_terms p))))) with
+      None -> assert false
+    | Some x ->
+       prerr_endline ("INSTANTIATING AND HOPING " ^ string_of_var x);
+       x)
+ with
+  Not_found -> x
+in*)
+ let special_k =
+     compute_special_k (Listx.from_list (all_terms p :> nf list) )in
+ if special_k < n then
+  prerr_endline ("@@@@ NEW INSTANTIATE PHASE (" ^ string_of_int special_k ^ ") @@@@");
+ let p = instantiate p x special_k in
+ special_k,p
+
+
+let rec auto_eat (n,({ps} as p)) =
+ prerr_endline "{{{{{{{{ Computing measure before auto_instantiate }}}}}}";
+ let m = problem_measure p in
+ let (n,p') = auto_instantiate (n,p) in
+ match eat p' with
+   `Finished p -> p
+ | `Continue p ->
+     prerr_endline "{{{{{{{{ Computing measure inafter auto_instantiate }}}}}}";
+     let delta = m - problem_measure p' in
+     if delta <= 0 then (
+      (* failwithProblem p' *)
+      prerr_endline
+      ("Measure did not decrease (delta=" ^ string_of_int delta ^ ")"))
+     else prerr_endline ("$ Measure decreased by " ^ string_of_int delta);
+     let p' = {p' with steps=(p'.steps - 1)} in
+     (if p'.steps < 0 then prerr_endline ">>>>>>>>>> STEPS ARE OVER <<<<<<<<<"
+     (*failwithProblem p' "steps are over. sorry."*) );
+     auto_eat (n,p)
+;;
+
+let auto p n =
+ prerr_endline ("@@@@ FIRST INSTANTIATE PHASE (" ^ string_of_int n ^ ") @@@@");
+ match eat p with
+   `Finished p -> p
+ | `Continue p -> auto_eat (n,p)
+;;
+
+(*
+0 = snd
+
+      x y = y 0    a y = k  k z = z 0  c y = k   y u = u h1 h2 0          h2 a = h3
+1 x a c    1 a 0 c  1 k c    1 c 0      1 k        1 k                     1 k
+2 x a y    2 a 0 y  2 k y    2 y 0      2 y 0      2 h2 0                  2 h3
+3 x b y    3 b 0 y  3 b 0 y  3 b 0 y    3 b 0 y    3 b 0 (\u. u h1 h2 0)   3 b 0 (\u. u h1 (\w.h3) 0)
+4 x b c    4 b 0 c  4 b 0 c  4 b 0 c    4 b 0 c    4 b 0 c                 4 b 0 c
+5 x (b e)  5 b e 0  5 b e 0  5 b e 0    5 b e 0    5 b e 0                 5 b e 0
+6 y y      6 y y    6 y y    6 y y      6 y y      6 h1 h1 h2 0 h2 0       6 h1 h1 (\w. h3) 0 (\w. h3) 0
+
+                                l2 _ = l3
+b u = u l1 l2 0                 e _ _ _ _ = f                         l3 n = n j 0
+1 k                             1 k                                  1 k
+2 h3                            2 h3                                 2 h3
+3 l2 0 (\u. u h1 (\w. h3) 0)    3 l3 (\u. u h1 (\w. h3) 0)           3 j h1 (\w. h3) 0 0
+4 l2 0 c                        4 l3 c                               4 c j 0
+5 e l1 l2 0 0                   5 f                                  5 f
+6 h1 h1 (\w. h3) 0 (\w. h3) 0   6 h1 h1 (\w. h3) 0 (\w. h3) 0        6 h1 h1 (\w. h3) 0 (\w. h3) 0
+*)
+
+(*
+                x n = n 0 ?
+x a (b (a c))   a 0 = 1 ? (b (a c))   8
+x a (b d')      a 0 = 1 ? (b d')      7
+x b (a c)       b 0 = 1 ? (a c)       4
+x b (a c')      b 0 = 1 ? (a c')      5
+
+c = 2
+c' = 3
+a 2 = 4  (* a c *)
+a 3 = 5  (* a c' *)
+d' = 6
+b 6 = 7  (* b d' *)
+b 4 = 8  (* b (a c) *)
+b 0 = 1
+a 0 = 1
+*)
+
+(************** Tests ************************)
+
+let optimize_numerals p =
+  let replace_in_sigma perm =
+    let rec aux = function
+    | `N n -> `N (List.nth perm n)
+    | `I _ -> assert false
+    | `Var _ as t -> t
+    | `Lam(v,t) -> `Lam(v, aux t)
+    | `Match(_,_,bs,_) as t -> (bs := List.map (fun (n,t) -> (List.nth perm n, t)) !bs); t
+    in List.map (fun (n,t) -> (n,aux t))
+  in
+  let deltas' = List.mapi (fun n d -> (n, List.map fst !d)) p.deltas in
+  let maxs = Array.to_list (Array.init (List.length deltas') (fun _ -> 0)) in
+  let max = List.fold_left max 0 (concat_map snd deltas') in
+  let perm,_ = List.fold_left (fun (perm, maxs) (curr_n:int) ->
+      let containing = filter_map (fun (i, bs) -> if List.mem curr_n bs then Some i else None) deltas' in
+      (* (prerr_endline (string_of_int curr_n ^ " occurs in: " ^ (String.concat " " (List.map string_of_int containing)))); *)
+      let neww = List.fold_left Pervasives.max 0 (List.mapi (fun n max -> if List.mem n containing then max else 0) maxs) in
+      let maxs = List.mapi (fun i m -> if List.mem i containing then neww+1 else m) maxs in
+      (neww::perm, maxs)
+    ) ([],maxs) (Array.to_list (Array.init (max+1) (fun x -> x))) in
+  replace_in_sigma (List.rev perm) p.sigma
+;;
+
+let env_of_sigma freshno sigma should_explode =
+ let rec aux n =
+  if n > freshno then
+   []
+  else
+   let e = aux (n+1) in
+   (try
+    e,Pure.lift (-n-1) (snd (List.find (fun (i,_) -> i = n) sigma)),[]
+   with
+    Not_found ->
+     if should_explode && `Var n = !bomb
+      then ([], (let f t = Pure.A(t,t) in f (Pure.L (f (Pure.V 0)))), [])
+      else ([],Pure.V n,[]))::e
+ in aux 0
+;;
+
+prerr_endline "########## main ##########";;
+
+(* Commands:
+    v ==> v := \a. a k1 .. kn \^m.0
+    + ==> v := \^k. numero  for every v such that ...
+    * ==> tries v as long as possible and then +v as long as possible
+*)
+let main problems =
+ let rec aux ({ps} as p) n l =
+  if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then begin
+   p
+  end else
+   let _ = prerr_endline (print_problem "main" p) in
+   let x,l =
+    match l with
+     | cmd::l -> cmd,l
+     | [] -> read_line (),[] in
+   let cmd =
+    if x = "+" then
+     `DoneWith
+    else if x = "*" then
+     `Auto
+    else
+     `Step x in
+   match cmd with
+    | `DoneWith -> assert false (*aux (eat p) n l*) (* CSC: TODO *)
+    | `Step x ->
+        let x = var_of_string x in
+        aux (instantiate p x n) n l
+    | `Auto -> aux (auto p n) n l
+ in
+  List.iter
+   (fun (p,n,cmds) ->
+    Console.print_hline();
+    bomb := `Var (-1);
+    let p_finale = aux p n cmds in
+    let freshno,sigma = p_finale.freshno, p_finale.sigma in
+    prerr_endline ("------- <DONE> ------\n " ^ (string_of_int (p.steps - p_finale.steps)) ^ " steps of "^ (string_of_int p.steps) ^".");
+    (* prerr_endline (print_problem "Original problem" p); *)
+    prerr_endline "---------------------";
+    let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
+    prerr_endline (" BOMB == " ^ print ~l !bomb);
+    prerr_endline "---------------------";
+    List.iter (fun (x,inst) -> prerr_endline (string_of_var x ^ " := " ^ print ~l inst)) sigma;
+(*
+     prerr_endline "----------------------";
+     let ps =
+      List.fold_left (fun ps (x,inst) ->
+       (* CSC: XXXX Is the subst always sorted correctly? Otherwise, implement a recursive subst *)
+       (* In this non-recursive version, the intermediate states may containt Matchs *)
+       List.map (fun t -> let t = subst false x inst (t :> nf) in cast_to_i_num_var t) ps)
+       (p.ps :> i_num_var list) sigma in
+     prerr_endline (print_problem {p with ps= List.map (function t -> cast_to_i_n_var t) ps; freshno});
+     List.iteri (fun i (n,more_args) -> assert (more_args = 0 && n = `N i)) ps ;
+*)
+    prerr_endline "---------<OPT>----------";
+    let sigma = optimize_numerals p_finale in (* optimize numerals *)
+    let l = Array.to_list (Array.init (freshno + 1) string_of_var) in
+    List.iter (fun (x,inst) -> prerr_endline (string_of_var x ^ " := " ^ print ~l inst)) sigma;
+    prerr_endline "---------<PURE>---------";
+    let div = option_map (fun div -> ToScott.t_of_nf (div :> nf)) p.div in
+    let conv = List.map (fun t -> ToScott.t_of_nf (t :> nf)) p.conv in
+    let ps = List.map (fun t -> ToScott.t_of_nf (t :> nf)) p.ps in
+    let sigma = List.map (fun (x,inst) -> x, ToScott.t_of_nf inst) sigma in
+    (*let ps_ok = List.fold_left (fun ps (x,inst) ->
+      List.map (Pure.subst false x inst) ps) ps sigma in*)
+    let e = env_of_sigma freshno sigma true in
+    let e' = env_of_sigma freshno sigma false in
+
+(*
+     prerr_endline "---------<PPP>---------";
+let rec print_e e =
+ "[" ^ String.concat ";" (List.map (fun (e,t,[]) -> print_e e ^ ":" ^ Pure.print t) e) ^ "]"
+in
+     prerr_endline (print_e e);
+     List.iter (fun (t,t_ok) ->
+      prerr_endline ("T0= " ^ Pure.print t ^ "\nTM= " ^ Pure.print (Pure.unwind (e,t,[])) ^ "\nOM= " ^ Pure.print t_ok);
+      (*assert (Pure.unwind (e,t,[]) = t_ok)*)
+     ) (List.combine ps ps_ok);
+*)
+     prerr_endline "--------<REDUCE>---------";
+     (function Some div ->
+      print_endline (Pure.print div);
+      let t = Pure.mwhd (e',div,[]) in
+      prerr_endline ("*:: " ^ (Pure.print t));
+      prerr_endline (print !bomb);
+      assert (t = ToScott.t_of_nf (!bomb:>nf))
+     | None -> ()) div;
+     List.iter (fun n ->
+       prerr_endline ("_::: " ^ (Pure.print n));
+       let t = Pure.mwhd (e,n,[]) in
+       prerr_endline ("_:: " ^ (Pure.print t))
+     ) conv ;
+     List.iteri (fun i n ->
+       prerr_endline ((string_of_int i) ^ "::: " ^ (Pure.print n));
+       let t = Pure.mwhd (e,n,[]) in
+       prerr_endline ((string_of_int i) ^ ":: " ^ (Pure.print t));
+       assert (t = Scott.mk_n i)
+     ) ps ;
+     prerr_endline "-------- </DONE> --------"
+   ) problems
+
+(********************** problems *******************)
+
+let zero = `Var 0;;
+
+let append_zero =
+ function
+  | `I _
+  | `Var _ as i ->  cast_to_i_n_var (mk_app i zero)
+  | _ -> assert false
+;;
+
+let bounds_on_steps all_tms =
+ let rec aux = function
+ | `I(k,args) -> Listx.fold_left (fun acc t -> 1 + acc + (aux t)) 0 args
+ | `Var _ -> 1
+ | `Lam (_, t) -> 1 + aux t
+ | _ -> assert false
+ in List.fold_right ((+) ++ aux) all_tms 0
+;;
+
+type t = problem * int * string list;;
+
+let magic_conv ~div ~conv ~nums cmds =
+ let all_tms = (match div with None -> [] | Some div -> [div]) @ nums @ conv in
+  let all_tms, var_names = parse' all_tms in
+  let steps = bounds_on_steps all_tms in
+  let div, (tms, conv) = match div with
+    | None -> None, list_cut (List.length nums, all_tms)
+    | Some _ -> Some (List.hd all_tms), list_cut (List.length nums, List.tl all_tms) in
+
+ if match div with None -> false | Some div -> List.exists (eta_subterm div) (tms@conv)
+ then (
+  prerr_endline "--- TEST SKIPPED ---";
+  {freshno=0; div=None; conv=[]; ps=[]; sigma=[]; deltas=[]; steps=(-1)}, 0, []
+ ) else
+  let tms = sort_uniq ~compare:eta_compare tms in
+  let special_k = compute_special_k (Listx.from_list all_tms) in (* compute initial special K *)
+  (* casts *)
+  let div = option_map cast_to_i_var div in
+  let conv = List.map cast_to_i_n_var conv in
+  let tms = List.map cast_to_i_n_var tms in
+
+  let ps = List.map append_zero tms in (* crea lista applicando zeri o dummies *)
+  let freshno = List.length var_names in
+  let deltas =
+   let dummy = `Var (max_int / 2) in
+    [ ref (Array.to_list (Array.init (List.length ps) (fun i -> i, dummy))) ] in
+
+  {freshno; div; conv; ps; sigma=[] ; deltas; steps}, special_k, cmds
+;;
+
+let magic strings cmds = magic_conv None [] strings cmds;;
diff --git a/ocaml/measure.ml b/ocaml/measure.ml
new file mode 100644 (file)
index 0000000..53b0fbc
--- /dev/null
@@ -0,0 +1,32 @@
+open Num;;\r
+open Lambda4;;\r
+\r
+(* type var = int;;\r
+\r
+type state = {\r
+ terms : nf list;\r
+ arities : (var * int) list;\r
+ freshno : int;\r
+ apps : (var * (var list)) list;\r
+}\r
+\r
+let replace =\r
+ function\r
+ | `Var _ | `Lam _ as t -> t\r
+ | `I(v,tms) ->\r
+   try\r
+    let apps = List.assoc v p.apps in\r
+    let hd, tl = ... in\r
+    let s, freshvar = mk_freshvar s\r
+    []\r
+    aux (mk_apps v (Listx.map ))\r
+   with\r
+   | Not_found -> `I(v, Listx.map (replace s) tms)\r
+ | _ -> assert false\r
+;;\r
+\r
+\r
+let iteration : state -> state  = fun s ->\r
+ let terms = Util.concat_map (replace s) s.terms in\r
+ s;;\r
+*)\r
index 6f3cae56c327c103eeb42c127bc626cbd28aa3eb..01787b02d1da3055087ae46bcf1c06cad70ea0e3 100644 (file)
@@ -138,7 +138,6 @@ let rec string_of_term l =
 ;;
 
 let print ?(l=[]) = string_of_term l;;
-let string_of_nf t = string_of_term [] (t:>nf);;
 
 (************ Hereditary substitutions ************************************)
 
@@ -292,3 +291,14 @@ let rec eta_subterm sub t =
 ;;
 
 let eta_subterm (#nf as x) (#nf as y) = eta_subterm x y;;
+
+let compute_special_k tms =
+  let rec aux k (t: nf) = Pervasives.max k (match t with
+    | `Lam(b,t) -> aux (k + if b then 1 else 0) t
+    | `I(n, tms) -> Listx.max (Listx.map (aux 0) tms)
+    | `Match(t, liftno, bs, args) ->
+        List.fold_left max 0 (List.map (aux 0) ((t :> nf)::args@List.map snd !bs))
+    | `N _ -> 0
+    | `Var _ -> 0
+  ) in Listx.max (Listx.map (aux 0) tms)
+;;
index 2f92884e92efddb0d9c51296950d7dc0261bf9eb..f81e445fc3eeeff6f3fac13a1b53d1473b06bb81 100644 (file)
@@ -28,7 +28,6 @@ module ToScott :
     val t_of_nf : nf -> Pure.Pure.t
   end
 val print : ?l:string list -> nf -> string
-val string_of_nf : [<nf] -> string
 val cast_to_i_var : [< nf > `I `Var] -> i_var
 val cast_to_i_n_var : [< nf > `I `N `Var] -> i_n_var
 val cast_to_i_num_var : [< nf > `I `N `Match `Var] -> i_num_var
@@ -41,3 +40,4 @@ val parse' : string list -> nf list * string list
 val eta_compare : nf -> nf -> int
 val eta_eq : [< nf ] -> [< nf ] -> bool
 val eta_subterm : [< nf ] -> [< nf ] -> bool
+val compute_special_k: nf Listx.listx -> int
diff --git a/ocaml/ptest.ml b/ocaml/ptest.ml
new file mode 100644 (file)
index 0000000..8a21229
--- /dev/null
@@ -0,0 +1,16 @@
+open Unix;;
+let process_output_to_list2 = fun command ->
+  let chan = open_process_in command in
+  let res = ref ([] : string list) in
+  let rec process_otl_aux () =
+    let e = input_line chan in
+    res := e::!res;
+    process_otl_aux() in
+  try process_otl_aux ()
+  with End_of_file ->
+    let stat = close_process_in chan in (List.rev !res,stat)
+let cmd_to_list command =
+  let (l,_) = process_output_to_list2 command in l;;
+
+let lines = cmd_to_list "tput cols" in
+prerr_endline (List.hd (lines));;
diff --git a/ocaml/tmp.ml b/ocaml/tmp.ml
new file mode 100644 (file)
index 0000000..624875f
--- /dev/null
@@ -0,0 +1,38 @@
+(((((((v (((a v) w) (((a v) w) v))) (w. c)) (b (a v))) c) (z. a)) (x. (w. (w. c)))) (((a (y c)) ((y c) ((a v) (w (z. a))))) (w. c)))\r
+((((((v (((a v) w) (((a v) w) v))) (w. c)) (b (a v))) c) (z. a)) (x. (w. (w. c))))\r
+(((((b (a v)) (a. (y c))) z) (w. w)) ((a c) c))\r
+(((((v (((a v) w) (((a v) w) v))) (w. c)) (b (a v))) c) (z. a))\r
+((((a (y c)) ((y c) ((a v) (w (z. a))))) (w. c)) (x. w))\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+let fancy_of_term : nf -> Console.fancyobj =\r
+  let open Console in\r
+  let of_var level n =\r
+    if n < level\r
+    then fancy_of_string (string_of_var n)\r
+    else (("x" ^ string_of_int (level-n-1)) / ("var<sup>" ^ string_of_int (n-level) ^ "</sup>"))\r
+  in let rec aux level = function\r
+    `Var n -> of_var level n\r
+  | `N n -> fancy_of_string (string_of_int n)\r
+  | `Match(t,bs_lift,bs,args) ->\r
+     "([" ^^ aux level (t :> nf) ^^\r
+     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (lift bs_lift t)) !bs) ^ "] " ^\r
+     String.concat " " (List.map (print ~l) args) ^ ")"\r
+  | `I(n,args) -> "(" ^ print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"\r
+  | `Lam nf ->\r
+     let name = string_of_var (List.length l) in\r
+     "λ" ^ name ^ "." ^ print ~l:(name::l) (nf : nf)\r
+  in aux 0\r
+;;\r