]> matita.cs.unibo.it Git - fireball-separation.git/commitdiff
Copy ocaml folder from sacerdot's svn repository, rev 4907
author <andrea.condoluci@unibo.it> <>
Mon, 12 Jun 2017 20:28:38 +0000 (22:28 +0200)
committer <andrea.condoluci@unibo.it> <>
Mon, 12 Jun 2017 20:28:38 +0000 (22:28 +0200)
31 files changed:
ocaml/Makefile [new file with mode: 0644]
ocaml/andrea3.ml [new file with mode: 0644]
ocaml/andrea5.ml [new file with mode: 0644]
ocaml/andrea6.ml [new file with mode: 0644]
ocaml/console.ml [new file with mode: 0644]
ocaml/console.mli [new file with mode: 0644]
ocaml/discriminator.mli [new file with mode: 0644]
ocaml/lambda3.ml [new file with mode: 0644]
ocaml/lambda3.ml.ar [new file with mode: 0644]
ocaml/lambda3.mli [new file with mode: 0644]
ocaml/lambda4.ml [new file with mode: 0644]
ocaml/lambda4.mli [new file with mode: 0644]
ocaml/listx.ml [new file with mode: 0644]
ocaml/listx.mli [new file with mode: 0644]
ocaml/mk_andrea [new file with mode: 0644]
ocaml/num.ml [new file with mode: 0644]
ocaml/num.ml.ar [new file with mode: 0644]
ocaml/num.mli [new file with mode: 0644]
ocaml/num.mli.ar [new file with mode: 0644]
ocaml/numx.ml [new file with mode: 0644]
ocaml/numx.mli [new file with mode: 0644]
ocaml/parser.ml [new file with mode: 0644]
ocaml/parser.mli [new file with mode: 0644]
ocaml/problems.ml [new file with mode: 0644]
ocaml/problems.mli [new file with mode: 0644]
ocaml/pure.ml [new file with mode: 0644]
ocaml/pure.mli [new file with mode: 0644]
ocaml/test.ml [new file with mode: 0644]
ocaml/test1.ml [new file with mode: 0644]
ocaml/util.ml [new file with mode: 0644]
ocaml/util.mli [new file with mode: 0644]

diff --git a/ocaml/Makefile b/ocaml/Makefile
new file mode 100644 (file)
index 0000000..3310c6e
--- /dev/null
@@ -0,0 +1,36 @@
+OCAMLC = ocamlopt -g -rectypes
+LIB = unix.cmxa str.cmxa
+UTILS = parser.cmx console.cmx listx.cmx util.cmx pure.cmx num.cmx
+
+all: a.out test.out test34.out
+
+a.out: $(UTILS) lambda3.cmx lambda4.cmx problems.cmx
+       $(OCAMLC) -o a.out $(LIB) $^
+
+test.out: $(UTILS) lambda3.cmx test1.ml
+       $(OCAMLC) -o test.out $(LIB) $^
+
+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
+
+#test2.out: $(UTILS) lambda3.ml test2.ml andrea
+#      ocamlc -o test2.out $(LIB) $(UTILS) lambda3.ml andrea4.ml test2.ml
+
+%.cmi: %.mli
+       $(OCAMLC) -c $<
+
+%.cmx: %.ml %.cmi
+       $(OCAMLC) -c $<
+
+clean:
+       rm -f *.cm* *.out .depend log
+
+.depend: *.ml *.mli
+       ocamldep *.ml *.mli > .depend
+
+include .depend
+
+.PHONY: clean all
diff --git a/ocaml/andrea3.ml b/ocaml/andrea3.ml
new file mode 100644 (file)
index 0000000..2796107
--- /dev/null
@@ -0,0 +1,364 @@
+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, None, 0);;\r
+let dummy = Tvar(333, None, 0);;\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)\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, None, x) -> Tvar(n-1, None, x)\r
+    | Tvar _ -> assert false\r
+    | Tapp(t1, t2) -> Tapp(minus1 t1, minus1 t2)\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, None, 0)\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 List.nth free (n) else List.nth bound (-n-1) 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
+    (* | (_, Some(n,t), _) -> "?" ^ string_of_int n *)\r
+    | (_, Some(n,t), _) -> "{" ^ (string_of_term_no_pars t) ^ "|" ^ (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 match t with\r
+    | (n, None, _) -> (string_of_int' n)\r
+    | (_, Some(n,t), _) -> "&alpha;<sup>" ^ (string_of_term_no_pars t) ^ "</sup><sub>" ^ (string_of_int n) ^ "</sub>"\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 -> Lambda3.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
+     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
+\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_html t\r
+;;\r
+\r
+let print_term t = print_endline (fancy_of_term t :> Console.fancyobj);;\r
+(*  *)\r
+\r
+\r
+let varcount = ref 0;;\r
+\r
+let freshvar () = (\r
+  varcount := (!varcount + 1);\r
+  !varcount\r
+);;\r
+\r
+let rec hd =\r
+  function\r
+  | Tvar x -> x\r
+  | Tapp(t1,t2) -> hd t1\r
+  | Tlam _ -> assert false\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 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 _ = 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 _ = 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
+;;\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 _ = 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
+;;\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/andrea5.ml b/ocaml/andrea5.ml
new file mode 100644 (file)
index 0000000..eadb645
--- /dev/null
@@ -0,0 +1,27 @@
+(* percorsi di differenza etc. *)\r
+\r
+open Lambda3;;\r
+\r
+type formula =\r
+  | Var of int\r
+  | And of formula * formula\r
+  | Or of formula * formula\r
+;;\r
+\r
+let rec mk_k_vars k =\r
+  if k = 0 then []\r
+  else `Var (k-1) :: (mk_k_vars (k-1))\r
+;;\r
+\r
+let is_lambda = function\r
+  | `Lam _ -> true\r
+  | _ -> false\r
+;;\r
+\r
+let rec diff k level t1 t2 =\r
+  if is_lambda t1 || is_lambda t2\r
+  then let vars = mk_k_vars k in\r
+       let level = level + k in\r
+       diff k level (mk_appl (lift k t1) vars) (mk_appl (lift k t2) vars)\r
+  else assert false\r
+;;\r
diff --git a/ocaml/andrea6.ml b/ocaml/andrea6.ml
new file mode 100644 (file)
index 0000000..34c0788
--- /dev/null
@@ -0,0 +1,474 @@
+let print_hline = Console.print_hline;;\r
+\r
+type var = int;;\r
+\r
+type t =\r
+ | V of var\r
+ | A of t * t\r
+ | L of t\r
+ | LM of\r
+    t list (* body of the match *)\r
+  * int (* explicit liftno *)\r
+  * int (* variable which originated this match (id) *)\r
+ | B (* bottom *)\r
+ | P (* pacman *)\r
+;;\r
+\r
+\r
+type problem = {\r
+   freshno : int\r
+ ; div : t\r
+ ; conv : t list\r
+ ; matches : (var (* variable originating this match *) * (t (* term to discriminate *) * t (* continuation *)) list) list\r
+ ; sigma : (var * t) list (* substitutions *)\r
+}\r
+\r
+let string_of_t p =\r
+ let bound_vars = ["x"; "y"; "z"; "z1"; "z2"] in\r
+ let rec aux level = function\r
+ | V v -> if v >= level then "`" ^ string_of_int (v-level) else List.nth bound_vars (level - v-1)\r
+ | A (t1,t2) -> "("^aux level t1^" "^aux level t2^")"\r
+ | L t -> "(\\" ^ aux (level+1) (V 0) ^ ". " ^ aux (level+1) t ^ ")"\r
+ | LM (ts,liftno,id) -> "[match orig="^aux 0 (V id)^"]"\r
+ | B -> "BOT"\r
+ | P -> "PAC"\r
+ in aux 0\r
+;;\r
+\r
+let string_of_problem p =\r
+ let lines = [\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 (_, lst) -> "[<>]" :: List.map (fun (t,c) -> "     " ^ 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 (string_of_problem p);\r
+ failwith 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 entry =\r
+ let matches = try\r
+   let _ = List.assoc id p.matches in\r
+   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
+;;\r
+\r
+let free_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
+ | L t -> aux (level+1) t\r
+ | LM(ts,_,_) -> List.fold_left (fun a b -> a || aux (level+1) b) false ts\r
+ | B -> false\r
+ | P -> false\r
+ in aux 0\r
+;;\r
+\r
+let rec is_inert =\r
+ function\r
+ | A(t,_) -> is_inert t\r
+ | L _ | LM _ | B -> false\r
+ | _ -> true\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
+ | 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
+     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
+ | 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
+ | LM(ts,liftno,id) ->\r
+  let p, t = mk_apps 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
+      p, newvar\r
+ | B\r
+ | _ 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 = 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
+ ;;\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, t = subst sub p t in\r
+  let p, tms = aux p tms in\r
+  p, t :: tms\r
+ in aux\r
+;;\r
+\r
+let rec subst_in_matches sub p =\r
+ function\r
+ | [] -> 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 branches = List.combine a b in\r
+  let p, ms = subst_in_matches sub p ms in\r
+  p, (v, branches) :: ms\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
+ 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 p, matches = subst_in_matches sub p p.matches in\r
+ {p with div=div; conv=conv; matches=matches; sigma=sub::p.sigma}\r
+;;\r
+\r
+(* FIXME *)\r
+let unify_terms p t1 t2 =\r
+ match t1 with\r
+ | V v -> subst_in_problem (v, t2) p\r
+ | _ -> problem_fail p "The collapse of a match came after too many steps :(";;\r
+\r
+let rec unify p =\r
+ 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
+  let rec aux = function\r
+   | [] -> [], None\r
+   | (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
+    ) in\r
+  function\r
+  | [] -> [], None\r
+  | (orig,branches) :: ms ->\r
+   match aux branches with\r
+   | _, None -> let ms, res = give_duplicates ms in (orig,branches) :: ms, res\r
+   | branches', Some subst -> (orig,branches') :: ms, Some subst in\r
+ let matches, vars_to_be_unified = give_duplicates p.matches in\r
+ let p = {p with matches=matches} in\r
+ match vars_to_be_unified with\r
+  | None -> p\r
+  | Some(t', t) ->\r
+   (* print_endline ("> unify " ^ string_of_t p (t') ^ " with " ^ string_of_t p t); *)\r
+   unify (unify_terms p t' t)\r
+;;\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
+;;\r
+\r
+exception Done;;\r
+\r
+let sanity p =\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
+\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
+ if problem_done p then raise Done else p\r
+;;\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
+ 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
+ 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
+ | _ -> 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
+ 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
+ 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
+ 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 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
+ 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 subst = var, t in\r
+ sanity (subst_in_problem subst p)\r
+;;\r
+\r
+(* TODO:\r
+- cosi' come e' possibile unificare rami di branch solo se vanno -> a variabili,\r
+  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
+\r
+let parse strs =\r
+ let dummy_p = {freshno=0; div=V 0; 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
+    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 freshno = 1 + List.length var_names in\r
+ let p = {freshno; 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
+  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 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 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
+ 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 = "id" then id (nth spl 1)\r
+    else failwith "unknown"\r
+    with Failure _ -> print_endline "Wrong input."; (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 -> List.iter print_endline (List.rev cmds)\r
+ in f p []\r
+;;\r
+\r
+let _ = magic6\r
+ "x x"\r
+ [ "_. BOMB" ]\r
+ [ ignore 1 1; explode ]\r
+;;\r
+\r
+ let _ = magic6\r
+    "x y BOMB b"\r
+  [ "x BOMB y c" ]\r
+  [ perm 1 3; step 1 ; ignore 8 2; explode; ];;\r
+\r
+let _ = magic6\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
+;;\r
+\r
+let _ = magic6\r
+ "x (x x)"\r
+ [ "x x" ; "x x x" ] [\r
+ apply 1 1;\r
+ step 1;\r
+ explode;\r
+ step 9;\r
+];;\r
+\r
+let _ = magic6\r
+ "x (_.BOMB)"\r
+ [ "x (_._. BOMB)" ]\r
+ [ apply 1 2; ]\r
+;;\r
+\r
+let _ = magic6\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 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
+;;\r
+\r
+let _ = magic6\r
+ "z (y x)"\r
+ [ "z (y (x.x))"; "y (_. BOMB)" ]\r
+ [ apply 2 1; step 3; explode' 8; ]\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
+ 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
+ explode;\r
+];;\r
+\r
+interactive\r
+  "y (x a)"\r
+[ "y (x b)"; "x BOMB"; "y a" ] [];;\r
+\r
+print_endline "ALL DONE. "\r
diff --git a/ocaml/console.ml b/ocaml/console.ml
new file mode 100644 (file)
index 0000000..696a74d
--- /dev/null
@@ -0,0 +1,141 @@
+type fancyobj = <
+  to_string : unit -> string;
+  to_html : unit -> string
+>;;
+
+let sepx = "\xe2\xbf\x96";;
+let endx = "\xe2\xbf\x97";;
+
+let socket_name = "/tmp/fancy.log";;
+
+let html_enabled = Sys.file_exists socket_name;;
+
+let socket = let open Unix in
+  if html_enabled
+  then socket PF_UNIX SOCK_STREAM 0
+  else socket PF_INET SOCK_STREAM 0;;
+
+let html_enabled = if html_enabled then
+  try
+    let _ = Unix.connect socket (Unix.ADDR_UNIX socket_name) in true
+  with Unix.Unix_error _ -> false
+  else false
+;;
+
+let cols =
+  let process_output_to_list2 = fun command ->
+    let chan = Unix.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 = Unix.close_process_in chan in (List.rev !res,stat)
+  in let cmd_to_list command =
+    let (l,_) = process_output_to_list2 command in l
+  in try let lines = cmd_to_list "tput cols" in int_of_string (List.hd (lines))
+  with _ -> 100 (* default value *)
+;;
+
+let writeall s =
+  let _ = Unix.send socket s 0 (String.length s) [] in ()
+;;
+
+let concat ls = (String.concat sepx ls) ^ endx;;
+
+(* HELO message *)
+if html_enabled then
+  writeall(concat["helo"; String.concat " " (Array.to_list Sys.argv)])
+;;
+
+
+(* let logs objs =
+  if html_enabled then (
+    let strs = (List.map (fun x -> x#to_html()) objs) in
+    writeall (concat ("log" :: strs))
+  ); prerr_endline (String.concat " " (List.map (fun x -> x#to_string()) objs))
+;; *)
+
+let html_escape s =
+  let m = [("&", "&amp;"); (">", "&gt;"); ("<", "&lt;"); ("&quot;", "\""); ("&#39;", "'")]
+  in let m = List.map (fun (x,y) -> Str.regexp x, y) m
+  in List.fold_right (fun (x,y) z -> Str.global_replace x y z) m s;; (* FIXME TODO *)
+
+let fancy_of_string s : fancyobj = object
+  method to_string () = s
+  method to_html () = html_escape s
+end;;
+
+let empty = fancy_of_string "";;
+
+let line = ref empty;;
+
+let (/) a b = object
+  method to_string () = a
+  method to_html () = b
+end;;
+
+let (^^) a b = object
+  method to_string () = (a#to_string () ^ "" ^ b#to_string ())
+  method to_html () = a#to_html () ^ " " ^ b#to_html ()
+end;;
+
+(* Output functions on standard output *)
+
+let print_string s =
+  line := !line ^^ fancy_of_string s
+;;
+
+let print_char c =
+  print_string (String.make 1 c)
+;;
+
+(* let print_bytes : bytes -> unit *)
+
+let print_int n =
+  print_string (string_of_int n)
+;;
+
+(* val print_float : float -> unit *)
+
+let print_newline () =
+  if !line <> empty then (
+  Pervasives.print_endline (!line#to_string());
+  if html_enabled then (writeall (concat ["log"; !line#to_html()]));
+  line := empty
+  )
+;;
+
+let print f =
+  line := !line ^^ f
+;;
+
+let print_string_endline f =
+  print (fancy_of_string f); print_newline ()
+;;
+
+let print_endline f =
+  print f; print_newline ()
+;;
+
+let print_hline () =
+  print_newline ();
+  print_endline ( String.make cols '-' / "<hr>")
+;;
+
+let print_heading s =
+  print_newline ();
+  print_endline (("# " ^ s) / ("<h2>" ^ html_escape s ^ "</h2>"))
+;;
+
+let print_bullet f =
+  print_newline ();
+  print_endline (("- " / "<ul><li>") ^^ f ^^ ("" / "</ul>"))
+;;
+
+let print_math s =
+  print_endline ( s / "" );
+  if html_enabled then (writeall (concat ["math"; s]))
+;;
diff --git a/ocaml/console.mli b/ocaml/console.mli
new file mode 100644 (file)
index 0000000..e3b769b
--- /dev/null
@@ -0,0 +1,24 @@
+type fancyobj\r
+\r
+val fancy_of_string: string -> fancyobj\r
+\r
+val (^^) : fancyobj -> fancyobj -> fancyobj\r
+val (/) : string -> string -> fancyobj\r
+\r
+\r
+val print_char : char -> unit\r
+val print_string : string -> unit\r
+val print_string_endline : string -> unit\r
+(* val print_bytes : bytes -> unit *)\r
+val print_int : int -> unit\r
+(* val print_float : float -> unit *)\r
+\r
+val print : fancyobj -> unit\r
+val print_endline : fancyobj -> unit\r
+\r
+val print_newline : unit -> unit\r
+\r
+val print_hline : unit -> unit\r
+val print_heading : string -> unit\r
+val print_bullet : fancyobj -> unit\r
+val print_math : string -> unit\r
diff --git a/ocaml/discriminator.mli b/ocaml/discriminator.mli
new file mode 100644 (file)
index 0000000..44ba167
--- /dev/null
@@ -0,0 +1,6 @@
+module type Discriminator = sig\r
+  type t\r
+  val magic: string list -> string list -> t\r
+  val magic_conv: div:(string option) -> conv:string list -> nums:string list -> string list -> t\r
+  val main: t list -> unit\r
+end\r
diff --git a/ocaml/lambda3.ml b/ocaml/lambda3.ml
new file mode 100644 (file)
index 0000000..f61e1e5
--- /dev/null
@@ -0,0 +1,550 @@
+open Util
+open Util.Vars
+open Pure
+open Num
+
+type problem =
+ { freshno: int
+ ; 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 *)
+ }
+
+let print_problem {freshno; ps; deltas} =
+ let deltas = String.concat "\n" (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
+ deltas ^ (if deltas = "" then "" else "\n") ^
+ String.concat "\n" (List.mapi (fun i t -> string_of_int i ^ ": " ^ print ~l (t :> nf)) ps)
+;;
+
+let make_fresh_var freshno =
+ freshno+1, freshno+1
+
+let make_fresh_vars p m =
+ let rec aux =
+  function
+     0 -> p.freshno,[]
+   | n when n > 0 ->
+      let freshno,vars = aux (n-1) in
+      let freshno,v = make_fresh_var freshno in
+      freshno,`Var v::vars
+   | _ -> assert false in
+ let freshno,vars = aux m in
+ {p with freshno}, vars
+
+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 rec super_simplify_ps ps it =
+  let it' = List.map (fun t -> cast_to_i_num_var (simple_expand_match ps t)) (it :> i_num_var list) in
+  if it <> it' then super_simplify_ps ps it' else it'
+
+let super_simplify ({ps} as p) =
+  let ps = super_simplify_ps p.ps (p.ps :> i_num_var list) in
+  {p with ps=List.map cast_to_i_n_var ps}
+
+let subst_in_problem x inst ({freshno; 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
+
+  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 = make_fresh_var freshno in
+           bs := !bs @ [i, `Var 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 _ ->
+         (* the cast will fail *)
+         (* freshno,(cast_to_i_n_var t),acc_new_ps *)
+         assert false
+    | #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 ps = List.map cast_to_i_n_var (old_ps @ new_ps) 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; ps; sigma = sigma@[x,inst]} in
+  let p = super_simplify p in
+prerr_endline (print_problem p); p
+
+exception Dangerous
+
+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 _,_,y = List.find (fun (v,_,_) -> v=k) arities in
+  let arity = match y with `Var _ -> 0 | `I(_,args) -> Listx.length args | _ -> assert false in
+  if List.length args + more_args > arity then raise Dangerous else ()
+ with
+  Not_found -> ()
+
+(* inefficient algorithm *)
+let edible arities showstoppers ps =
+ 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
+  aux showstoppers ps
+
+let precompute_edible_data {ps} xs =
+ List.map (fun x ->
+  let y = List.find (fun y -> hd_of y = Some x) ps in
+  x, index_of ~eq:eta_eq y ps, y) xs
+;;
+
+let critical_showstoppers p =
+  let p = super_simplify p in
+  let showstoppers_step =
+  List.concat (List.map (fun bs ->
+    let heads = List.map (fun (i,_) -> List.nth p.ps i) !bs in
+    let heads = List.sort compare (filter_map hd_of heads) in
+    snd (split_duplicates heads)
+    ) p.deltas) 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 = edible arities showstoppers ps 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)) ->
+   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));
+   (* CSC: XXX to avoid applied numbers in safe positions that
+      trigger assert failures subst_in_problem x inst p*)
+   { p with sigma = p.sigma @ [x,inst] }
+  ) p l in
+ 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
+ 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 p = { p with ps } in
+ if l <> [] then prerr_endline (print_problem p);
+ if List.for_all (function `N _ -> true | _ -> false) ps then
+  `Finished p
+ else
+  `Continue p
+
+let instantiate p x n =
+  let p,vars = make_fresh_vars p n in
+  let freshno,zero = make_fresh_var p.freshno in
+  let p = {p with freshno} in
+  let zero = Listx.Nil (`Var 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 ({ps} as 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) 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) ps) 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) ps)))) 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 (p.ps :> 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 problem_measure {ps} =
+  (* let rec term_size_i_n_var =
+    function
+    | `I(v,nfs) ->
+      (Listx.length nfs) *
+      (List.fold_right (fun (a,b) c -> 10 + ((a+1) * term_size b) + c) (List.mapi (fun x y -> (x,y)) (Listx.to_list nfs)) 0)
+    | `Var _ -> 1
+    | `N _ -> 0
+  and term_size =
+    function
+    | #i_n_var as t -> term_size_i_n_var t
+    | `Match(t,lift,bs,args) -> 1 + (term_size (t :> nf)) + 1 + (List.fold_right ((+) ++ term_size) args 0)
+    | `Lam(b,t) -> (if b then 0 else 1) + term_size t
+  (* in List.fold_right ((+) ++ term_size_i_n_var) ps 0;; *)
+  in ... *)
+  0
+
+let rec auto_eat (n,({ps} as p)) =
+ match eat p with
+    `Finished p -> p
+  | `Continue p ->
+    let p' = auto_instantiate (n,p) in
+    let m' = problem_measure (snd p') in
+    let delta = m' - problem_measure p in
+    (if delta >= 0
+    then print_endline ("$$$$ MEASURE DID NOT DECREASE (after inst) delta=" ^ string_of_int delta));
+    let p'' = auto_eat p' in
+    (if m' <= problem_measure p''
+    then print_endline ("$$$$ MEASURE DID NOT DECREASE (after eat) $$$"));
+    p''
+;;
+
+let auto p n =
+ prerr_endline ("@@@@ FIRST INSTANTIATE PHASE (" ^ string_of_int n ^ ") @@@@");
+ 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 _ | `Var _ -> assert false
+    | `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 = Listx.max (Listx.from_list (
+    List.concat (List.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 = Listx.max (Listx.from_list (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
+;;
+
+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 then begin
+   assert (l = []);
+   p
+  end else
+   let _ = prerr_endline (print_problem 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) ->
+     let p_finale = aux p n cmds in
+     let freshno,sigma = p_finale.freshno, p_finale.sigma in
+     prerr_endline "------- <DONE> ------";
+     prerr_endline (print_problem p);
+     prerr_endline "---------------------";
+     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 "----------------------";
+     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 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 =
+      let rec aux n =
+       if n > freshno then
+        []
+       else
+        let e = aux (n+1) in
+        (try
+         e,Pure.lift (-n-1) (let t = (snd (List.find (fun (i,_) -> i = n) sigma)) in prerr_endline (string_of_var n ^ " := " ^ Pure.print t); t),[]
+        with
+         Not_found -> [],Pure.V n,[])::e
+      in
+       aux 0 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>---------";
+     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
+;;
+
+type t = problem * int * string list;;
+
+let magic strings cmds =
+  let tms, _ = parse' strings in (*  *)
+  let tms = sort_uniq ~compare:eta_compare tms in
+  let special_k = compute_special_k (Listx.from_list tms) in (* compute special K *)
+  let fv = sort_uniq (List.concat (List.map free_vars tms)) in (* free variables *)
+  let tms = List.map cast_to_i_n_var tms in (* cast nf list -> i_n_var list *)
+  let ps = List.map append_zero tms in (* crea lista applicando zeri o dummies *)
+  (*let _ =  prerr_endline ("Free vars: " ^ String.concat ", " (List.map string_of_var fv)) in*)
+  let freshno = Listx.max (Listx.from_list fv) in
+  let dummy = `Var (max_int / 2) in
+  let deltas = [ ref (Array.to_list (Array.init (List.length ps) (fun i -> i, dummy))) ] in
+  {freshno; ps; sigma=[] ; deltas}, special_k, cmds
+;;
+
+let magic_conv ~div:_ ~conv:_ ~nums:_ _ = assert false;;
diff --git a/ocaml/lambda3.ml.ar b/ocaml/lambda3.ml.ar
new file mode 100644 (file)
index 0000000..39e77a7
--- /dev/null
@@ -0,0 +1,550 @@
+open Util
+open Util.Vars
+open Pure
+open Num
+
+type problem =
+ { freshno: int
+ ; 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 *)
+ }
+
+let print_problem {freshno; ps; deltas} =
+ let deltas = String.concat "\n" (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
+ deltas ^ (if deltas = "" then "" else "\n") ^
+ String.concat "\n" (List.mapi (fun i t -> string_of_int i ^ ": " ^ print ~l (t :> nf)) ps)
+;;
+
+let make_fresh_var freshno =
+ freshno+1, freshno+1
+
+let make_fresh_vars p m =
+ let rec aux =
+  function
+     0 -> p.freshno,[]
+   | n when n > 0 ->
+      let freshno,vars = aux (n-1) in
+      let freshno,v = make_fresh_var freshno in
+      freshno,`Var (0,v)::vars
+   | _ -> assert false in
+ let freshno,vars = aux m in
+ {p with freshno}, vars
+
+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(ar,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 ar (`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(ar,cast_to_i_num_var u,bs_lift,bs,List.map (aux level) args))
+  | `I(ar,k,args) -> `I(ar,k,Listx.map (aux level) args)
+  | `N _ | `Var _ as t -> t
+in aux_i_num_var 0;;
+
+let rec super_simplify_ps ps it =
+  let it' = List.map (fun t -> cast_to_i_num_var (simple_expand_match ps t)) (it :> i_num_var list) in
+  if it <> it' then super_simplify_ps ps it' else it'
+
+let super_simplify ({ps} as p) =
+  let ps = super_simplify_ps p.ps (p.ps :> i_num_var list) in
+  {p with ps=List.map cast_to_i_n_var ps}
+
+let subst_in_problem x inst ({freshno; 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(-1,max_int/3)::todo_ps,acc_new_ps) t
+       in
+        aux (freshno,acc_ps@[new_t],acc_new_ps) todo_ps
+
+  and expand_match ((freshno,acc_ps, acc_new_ps) as acc) t =
+   match t with
+    | `Match(ar,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 = make_fresh_var freshno in
+           bs := !bs @ [i, `Var (ar - 1,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 ar (`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 _ ->
+         (* the cast will fail *)
+         (* freshno,(cast_to_i_n_var t),acc_new_ps *)
+         assert false
+    | #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 ps = List.map cast_to_i_n_var (old_ps @ new_ps) 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; ps; sigma = sigma@[x,inst]} in
+  let p = super_simplify p in
+prerr_endline (print_problem p); p
+
+exception Dangerous
+
+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 _,_,y = List.find (fun (v,_,_) -> v=k) arities in
+  let arity = match y with `Var _ -> 0 | `I(_,_,args) -> Listx.length args | _ -> assert false in
+  if List.length args + more_args > arity then raise Dangerous else ()
+ with
+  Not_found -> ()
+
+(* inefficient algorithm *)
+let edible arities showstoppers ps =
+ 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
+  aux showstoppers ps
+
+let precompute_edible_data {ps} xs =
+ List.map (fun x ->
+  let y = List.find (fun y -> hd_of y = Some x) ps in
+  x, index_of ~eq:eta_eq y ps, y) xs
+;;
+
+let critical_showstoppers p =
+  let p = super_simplify p in
+  let showstoppers_step =
+  List.concat (List.map (fun bs ->
+    let heads = List.map (fun (i,_) -> List.nth p.ps i) !bs in
+    let heads = List.sort compare (filter_map hd_of heads) in
+    snd (split_duplicates heads)
+    ) p.deltas) 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 = edible arities showstoppers ps 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)) ->
+   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));
+   (* CSC: XXX to avoid applied numbers in safe positions that
+      trigger assert failures subst_in_problem x inst p*)
+   { p with sigma = p.sigma @ [x,inst] }
+  ) p l in
+ 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
+ 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 p = { p with ps } in
+ if l <> [] then prerr_endline (print_problem p);
+ if List.for_all (function `N _ -> true | _ -> false) ps then
+  `Finished p
+ else
+  `Continue p
+
+let instantiate p x n =
+  let p,vars = make_fresh_vars p n in
+  let freshno,zero = make_fresh_var p.freshno in
+  let p = {p with freshno} in
+  let zero = Listx.Nil (`Var (0,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(-1,`I(-1,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 ({ps} as 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) 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) ps) 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) ps)))) 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 (p.ps :> 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 problem_measure {ps} =
+  (* let rec term_size_i_n_var =
+    function
+    | `I(v,nfs) ->
+      (Listx.length nfs) *
+      (List.fold_right (fun (a,b) c -> 10 + ((a+1) * term_size b) + c) (List.mapi (fun x y -> (x,y)) (Listx.to_list nfs)) 0)
+    | `Var _ -> 1
+    | `N _ -> 0
+  and term_size =
+    function
+    | #i_n_var as t -> term_size_i_n_var t
+    | `Match(t,lift,bs,args) -> 1 + (term_size (t :> nf)) + 1 + (List.fold_right ((+) ++ term_size) args 0)
+    | `Lam(b,t) -> (if b then 0 else 1) + term_size t
+  (* in List.fold_right ((+) ++ term_size_i_n_var) ps 0;; *)
+  in ... *)
+  0
+
+let rec auto_eat (n,({ps} as p)) =
+ match eat p with
+    `Finished p -> p
+  | `Continue p ->
+    let p' = auto_instantiate (n,p) in
+    let m' = problem_measure (snd p') in
+    let delta = m' - problem_measure p in
+    (if delta >= 0
+    then print_endline ("$$$$ MEASURE DID NOT DECREASE (after inst) delta=" ^ string_of_int delta));
+    let p'' = auto_eat p' in
+    (if m' <= problem_measure p''
+    then print_endline ("$$$$ MEASURE DID NOT DECREASE (after eat) $$$"));
+    p''
+;;
+
+let auto p n =
+ prerr_endline ("@@@@ FIRST INSTANTIATE PHASE (" ^ string_of_int n ^ ") @@@@");
+ 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 _ | `Var _ -> assert false
+    | `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 = Listx.max (Listx.from_list (
+    List.concat (List.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 = Listx.max (Listx.from_list (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
+;;
+
+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 then begin
+   assert (l = []);
+   p
+  end else
+   let _ = prerr_endline (print_problem 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) ->
+     let p_finale = aux p n cmds in
+     let freshno,sigma = p_finale.freshno, p_finale.sigma in
+     prerr_endline "------- <DONE> ------";
+     prerr_endline (print_problem p);
+     prerr_endline "---------------------";
+     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 "----------------------";
+     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 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 =
+      let rec aux n =
+       if n > freshno then
+        []
+       else
+        let e = aux (n+1) in
+        (try
+         e,Pure.lift (-n-1) (let t = (snd (List.find (fun (i,_) -> i = n) sigma)) in prerr_endline (string_of_var n ^ " := " ^ Pure.print t); t),[]
+        with
+         Not_found -> [],Pure.V n,[])::e
+      in
+       aux 0 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>---------";
+     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,0);;
+
+let append_zero =
+ function
+  | `I _
+  | `Var _ as i ->  cast_to_i_n_var (mk_app i zero)
+  | _ -> assert false
+;;
+
+type t = problem * int * string list;;
+
+let magic strings cmds =
+  let tms, _ = parse' strings in (*  *)
+  let tms = sort_uniq ~compare:eta_compare tms in
+  let special_k = compute_special_k (Listx.from_list tms) in (* compute special K *)
+  let fv = sort_uniq (List.concat (List.map free_vars tms)) in (* free variables *)
+  let tms = List.map cast_to_i_n_var tms in (* cast nf list -> i_n_var list *)
+  let ps = List.map append_zero tms in (* crea lista applicando zeri o dummies *)
+  (*let _ =  prerr_endline ("Free vars: " ^ String.concat ", " (List.map string_of_var fv)) in*)
+  let freshno = Listx.max (Listx.from_list fv) in
+  let dummy = `Var (-1,max_int / 2) in
+  let deltas = [ ref (Array.to_list (Array.init (List.length ps) (fun i -> i, dummy))) ] in
+  {freshno; ps; sigma=[] ; deltas}, special_k, cmds
+;;
+
+let magic_conv ~div:_ ~conv:_ ~nums:_ _ = assert false;;
diff --git a/ocaml/lambda3.mli b/ocaml/lambda3.mli
new file mode 100644 (file)
index 0000000..cbaf41c
--- /dev/null
@@ -0,0 +1 @@
+include Discriminator.Discriminator\r
diff --git a/ocaml/lambda4.ml b/ocaml/lambda4.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/lambda4.mli b/ocaml/lambda4.mli
new file mode 100644 (file)
index 0000000..cbaf41c
--- /dev/null
@@ -0,0 +1 @@
+include Discriminator.Discriminator\r
diff --git a/ocaml/listx.ml b/ocaml/listx.ml
new file mode 100644 (file)
index 0000000..ecc8a92
--- /dev/null
@@ -0,0 +1,68 @@
+(* Non-empty lists *)
+type 'a listx =
+  | Nil of 'a
+  | Cons of ('a * 'a listx)
+
+let rec fold_left f acc l =
+  match l with
+  | Nil x -> f acc x
+  | Cons (x, l') -> fold_left f (f acc x) l'
+
+let hd =
+ function
+  | Nil x
+  | Cons (x,_) -> x
+
+let rec map f =
+  function
+  | Nil x -> Nil (f x)
+  | Cons (x, l') -> Cons (f x, map f l')
+
+let rec append l =
+  function
+  | Nil x -> Cons (x, l)
+  | Cons (x, l') -> Cons (x, append l l')
+
+let rec length = function
+  | Nil _ -> 1
+  | Cons (_, xs) -> 1 + (length xs)
+
+let rec assoc x = function
+  | Nil (y,t)
+  | Cons ((y,t),_) when x=y -> t
+  | Nil _ -> raise Not_found
+  | Cons (_,l) -> assoc x l
+
+let rec to_list =
+ function
+    Nil x -> [x]
+  | Cons (x,l) -> x::to_list l
+
+let rec from_list =
+ function
+    [] -> raise (Failure "from_list: empty list")
+  | [x] -> Nil x
+  | x::l -> Cons(x,from_list l)
+
+let rec split_nth n l =
+ match n,l with
+    0,_ -> []
+ | 1,Nil x -> [x]
+ | n,Cons (hd,tl) -> hd::split_nth (n-1) tl
+ | _,_ -> raise (Failure "split_nth: not enough args")
+
+let rec max =
+  function
+  | Nil x -> x
+  | Cons (x, l) -> Pervasives.max x (max l)
+
+(*
+let rec nth i l = match l, i with
+ | Cons (x, _), 1  -> x
+ | _, n when n <= 0 -> raise (Invalid_argument "Listx.nth")
+ | Cons (_, xs), n -> nth (n-1) xs
+ | Nil x, 1        -> x
+ | Nil _, _        -> raise (Invalid_argument "Listx.nth")
+;;
+*)
+
diff --git a/ocaml/listx.mli b/ocaml/listx.mli
new file mode 100644 (file)
index 0000000..97226ae
--- /dev/null
@@ -0,0 +1,11 @@
+type 'a listx = Nil of 'a | Cons of ('a * 'a listx)
+val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b listx -> 'a
+val hd : 'a listx -> 'a
+val map : ('a -> 'b) -> 'a listx -> 'b listx
+val append : 'a listx -> 'a listx -> 'a listx
+val length : 'a listx -> int
+val assoc : 'a -> ('a * 'b) listx -> 'b
+val to_list : 'a listx -> 'a list
+val from_list : 'a list -> 'a listx
+val split_nth : int -> 'a listx -> 'a list
+val max : 'a listx -> 'a
diff --git a/ocaml/mk_andrea b/ocaml/mk_andrea
new file mode 100644 (file)
index 0000000..a29f203
--- /dev/null
@@ -0,0 +1,3 @@
+ocamlc -c parser.ml\r
+ocamlc -o andrea andrea.ml parser.cmo\r
+./andrea\r
diff --git a/ocaml/num.ml b/ocaml/num.ml
new file mode 100644 (file)
index 0000000..6f3cae5
--- /dev/null
@@ -0,0 +1,294 @@
+open Util
+open Util.Vars
+open Pure
+
+(************ Syntax ************************************)
+
+(* Normal forms*)
+
+(* Var n = n-th De Bruijn index, 0-based *)
+
+(*type nf =
+  | Lam of nf
+  | Var of int
+  | i
+and i =
+  | I of int * nf listx
+;;*)
+type 'nf i_var_ = [ `I of int * 'nf Listx.listx | `Var of int ]
+type 'nf i_n_var_ = [ `N of int | 'nf i_var_ ]
+type 'nf i_num_var_ = [
+  | 'nf i_n_var_
+  | `Match of 'nf i_num_var_ * (*lift*) int * (*branches*)(int * 'nf) list ref * (*args*)'nf list
+]
+type 'nf nf_ = [ `Lam of (* was_unpacked *) bool * 'nf nf_ | 'nf i_num_var_ ]
+type nf = nf nf_
+type i_var = nf i_var_;;
+type i_n_var = nf i_n_var_;;
+type i_num_var = nf i_num_var_;;
+
+let hd_of_i_var =
+ function
+   `I (v,_)
+ | `Var v -> v
+
+let hd_of =
+ function
+   `I (v,_)
+ | `Var v -> Some v
+ | `N _ -> None
+ | `Match _ -> assert false
+
+let lift m (t : nf) =
+ let rec aux_i_num_var l =
+  function
+    `I(n,args) -> (`I((if n < l then n else n+m),Listx.map (aux l) args) : i_num_var)
+   | `Var n -> `Var (if n < l then n else n+m)
+   | `N _ as x -> x
+   | `Match(t,lift,bs,args) ->
+      `Match(aux_i_num_var l t, lift + m, bs, List.map (aux l) args)
+ and aux l =
+  function
+     #i_num_var as x -> (aux_i_num_var l x :> nf)
+   | `Lam(b,nf) -> `Lam (b,aux (l+1) nf)
+ in
+  (aux 0 t : nf)
+;;
+
+(* put t under n lambdas, lifting t accordingtly *)
+let rec make_lams t =
+ function
+   0 -> t
+ | n when n > 0 -> `Lam (false,lift 1 (make_lams t (n-1)))
+ | _ -> assert false
+
+let free_vars =
+ let rec aux n = function
+    `N _ -> []
+  | `Var x -> if x < n then [] else [x-n]
+  | `I(x,args) ->
+      (if x < n then [] else [x-n]) @
+      List.concat (List.map (aux n) (Listx.to_list args))
+  | `Lam(_,t) -> aux (n+1) t
+  | `Match(t,liftno,bs,args) ->
+      aux n (t :> nf) @
+      List.concat (List.map (fun (_,t) -> aux (n-liftno) t) !bs) @
+      List.concat (List.map (aux n) args)
+  in aux 0
+;;
+
+module ToScott =
+struct
+
+let rec t_of_i_num_var =
+ function
+  | `N n -> Scott.mk_n n
+  | `Var v -> Pure.V v
+  | `Match(t,liftno,bs,args) ->
+      let bs = List.map (fun (n,t) -> n, t_of_nf (lift liftno t)) !bs in
+      let t = t_of_i_num_var t in
+      let m = Scott.mk_match t bs in
+      List.fold_left (fun acc t -> Pure.A(acc,t_of_nf t)) m args
+  | `I(v, args) -> Listx.fold_left (fun acc t -> Pure.A(acc,t_of_nf t)) (Pure.V v) args
+and t_of_nf =
+ function
+  | #i_num_var as x -> t_of_i_num_var x
+  | `Lam(b,f) -> Pure.L (t_of_nf f)
+
+end
+
+
+(************ Pretty-printing ************************************)
+
+let rec print ?(l=[]) =
+ function
+    `Var n -> print_name l n
+  | `N n -> string_of_int n
+  | `Match(t,bs_lift,bs,args) ->
+     "([" ^ print ~l (t :> nf) ^
+     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (lift bs_lift t)) !bs) ^ "] " ^
+     String.concat " " (List.map (print ~l) args) ^ ")"
+  | `I(n,args) -> "(" ^ print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"
+  | `Lam(_,nf) ->
+     let name = string_of_var (List.length l) in
+     "λ" ^ name ^ "." ^ print ~l:(name::l) (nf : nf)
+;;
+
+let rec string_of_term l =
+ let rec string_of_term_w_pars l = function
+  | `Var n -> print_name l n
+  | `N n -> string_of_int n
+  | `I _ as t -> "(" ^ string_of_term_no_pars_app l (t :> nf) ^ ")"
+  | `Lam _ as t -> "(" ^ string_of_term_no_pars_lam l t ^ ")"
+  | `Match(t,bs_lift,bs,args) ->
+     "(match " ^ string_of_term_no_pars l (t :> nf) ^
+     " with " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ string_of_term l (lift bs_lift t)) !bs) ^ "] " ^
+     String.concat " " (List.map (string_of_term l) args) ^ ")"
+ and string_of_term_no_pars_app l = function
+  | `I(n, args) -> print_name l n ^ " " ^ String.concat " " (List.map (string_of_term_w_pars l) (Listx.to_list args))
+  | #nf as t -> string_of_term_w_pars l t
+ and string_of_term_no_pars_lam l  = function
+  | `Lam(_,t) -> let name = string_of_var (List.length l) in
+   "λ" ^ name ^ ". " ^ (string_of_term_no_pars_lam (name::l) t)
+  | _ as t -> string_of_term_no_pars l t
+ and string_of_term_no_pars l : nf -> string = function
+  | `Lam _ as t -> string_of_term_no_pars_lam l t
+  | #nf as t -> string_of_term_no_pars_app l t
+ in string_of_term_no_pars l
+;;
+
+let print ?(l=[]) = string_of_term l;;
+let string_of_nf t = string_of_term [] (t:>nf);;
+
+(************ Hereditary substitutions ************************************)
+
+let cast_to_i_var =
+ function
+    #i_var as y -> (y : i_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let cast_to_i_n_var =
+ function
+    #i_n_var as y -> (y : i_n_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let cast_to_i_num_var =
+ function
+    #i_num_var as y -> (y : i_num_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let rec mk_app (h : nf) (arg : nf) =
+(*let res =*)
+ match h with
+    `I(n,args) -> `I(n,Listx.append (Listx.Nil arg) args)
+  | `Var n -> `I(n, Listx.Nil arg)
+  | `Lam(_,nf) -> subst true 0 arg (nf : nf)
+  | `Match(t,lift,bs,args) -> `Match(t,lift,bs,List.append args [arg])
+  | `N _ -> assert false (* Numbers cannot be applied *)
+(*in let l = ["v0";"v1";"v2"] in
+prerr_endline ("mk_app h:" ^ print ~l h ^ " arg:" ^ print ~l:l arg ^ " res:" ^ print ~l:l res); res*)
+
+and mk_appl h args =
+ (*prerr_endline ("MK_APPL: " ^ print h ^ " " ^ String.concat " " (List.map print args));*)
+ List.fold_left mk_app h args
+
+and mk_appx h args = Listx.fold_left mk_app h args
+
+and mk_match t bs_lift bs args =
+ (*prerr_endline ("MK_MATCH: ([" ^ print t ^ "] " ^ String.concat " " (Listx.to_list (Listx.map (fun (n,t) -> string_of_int n ^ " => " ^ print t) bs)) ^ ") " ^ String.concat " " (List.map print args));*)
+ match t with
+    `N m ->
+      (try
+        let h = List.assoc m !bs in
+        let h = lift bs_lift h in
+        mk_appl h args
+       with Not_found ->
+        `Match (t,bs_lift,bs,args))
+  | `I _ | `Var _ | `Match _ -> `Match(t,bs_lift,bs,args)
+
+and subst delift_by_one what (with_what : nf) (where : nf) =
+ let rec aux_i_num_var l =
+  function
+     `I(n,args) ->
+       if n = what + l then
+        mk_appx (lift l with_what) (Listx.map (aux l) args)
+       else
+        `I ((if delift_by_one && n >= l then n-1 else n), Listx.map (aux l) args)
+   | `Var n ->
+       if n = what + l then
+        lift l with_what
+       else
+        `Var (if delift_by_one && n >= l then n-1 else n)
+   | `N _ as x -> x
+   | `Match(t,bs_lift,bs,args) ->
+       let bs_lift = bs_lift + if delift_by_one then -1 else 0 in
+       let l' = l - bs_lift  in
+       let with_what' = lift l' with_what in
+       (* The following line should be the identity when delift_by_one = true because we
+          are assuming the ts to not contain lambda-bound variables. *)
+       bs := List.map (fun (n,t) -> n,subst false what with_what' t) !bs ;
+       mk_match (cast_to_i_num_var (aux_i_num_var l t)) bs_lift bs (List.map (aux l) args)
+ and aux l(*lift*) =
+(*function iii -> let res = match iii with*)
+  function
+   | #i_num_var as x -> aux_i_num_var l x
+   | `Lam(b,nf) -> `Lam(b,aux (l+1) nf)
+(*in let ll = ["v0";"v1";"v2"] in
+prerr_endline ("subst l:" ^ string_of_int l ^ " delift_by_one:" ^ string_of_bool delift_by_one ^ " what:" ^ (List.nth ll what) ^ " with_what:" ^ print ~l:ll with_what ^ " where:" ^ print ~l:ll iii ^ " res:" ^ print ~l:ll res); res*)
+ in
+  aux 0 where
+;;
+
+(************ Parsing ************************************)
+
+let parse' strs =
+  let rec aux = function
+  | Parser.Lam t -> `Lam (true,aux t)
+  | Parser.App (t1, t2) -> mk_app (aux t1) (aux t2)
+  | Parser.Var v -> `Var v
+  in let (tms, free) = Parser.parse_many strs
+  in (List.map aux tms, free)
+;;
+
+(************** Algorithm(s) ************************)
+
+let eta_compare x y =
+ (* let clex a b = let diff = ? a b in if diff = 0 then cont () else 0 in *)
+ let clex aux1 aux2 (a1,a2) (b1,b2) =
+  let diff = aux1 a1 b1 in if diff = 0 then aux2 a2 b2 else diff in
+ let rec lex aux l1 l2 =
+  match l1,l2 with
+ | [], [] -> 0
+ | [], _ -> -1
+ | _, [] -> 1
+ | x::xs, y::ys -> clex aux (lex aux) (x,xs) (y,ys) in
+ let rec aux t1 t2 = match t1, t2 with
+  | `Var n , `Var m -> compare n m
+  | `I(n1, l1), `I(n2, l2) ->
+    clex compare (lex aux) (n1, Listx.to_list l1) (n2, Listx.to_list l2)
+  | `Lam _, `N _ -> -1
+  | `N _, `Lam _ -> 1
+  | `Lam(_,t1), `Lam(_,t2) -> aux t1 t2
+  | `Lam(_,t1), t2 -> - aux t1 (mk_app (lift 1 t2) (`Var 0))
+  | t2, `Lam(_,t1) ->   aux t1 (mk_app (lift 1 t2) (`Var 0))
+  | `N n1, `N n2 -> compare n1 n2
+  | `Match(u,bs_lift,bs,args), `Match(u',bs_lift',bs',args') ->
+    let bs = List.sort (fun (n,_) (m,_) -> compare n m) !bs in
+    let bs' = List.sort (fun (n,_) (m,_) -> compare n m) !bs' in
+    clex aux (clex (lex (clex compare aux)) (lex aux)) ((u :> nf), (bs, args)) ((u' :> nf), (bs', args'))
+  | `Match _, _ -> -1
+  | _, `Match _ -> 1
+  | `N _, _ -> -1
+  | _, `N _ -> 1
+  | `I _, _ -> -1
+  | _, `I _ -> 1
+  in aux x y
+;;
+
+let eta_eq (#nf as x) (#nf as y) = 0 = eta_compare x y ;;
+
+let rec eta_subterm sub t =
+ if eta_eq sub t then true else
+  match t with
+  | `Lam(_,t') -> eta_subterm (lift 1 sub) t'
+  | `Match(u,liftno,bs,args) ->
+     eta_subterm sub (u :> nf)
+     || List.exists (fun (_, t) -> eta_subterm sub (lift liftno t)) !bs
+     || List.exists (eta_subterm sub) args
+  | `I(v, args) -> List.exists (eta_subterm sub) (Listx.to_list args) || (match sub with
+   | `Var v' -> v = v'
+   | `I(v', args') -> v = v'
+    && Listx.length args' < Listx.length args
+    && List.for_all (fun (x,y) -> eta_eq x y) (List.combine (Util.take (Listx.length args') (Listx.to_list args)) (Listx.to_list args'))
+   | _ -> false
+   )
+  | `N _ | `Var _ -> false
+;;
+
+let eta_subterm (#nf as x) (#nf as y) = eta_subterm x y;;
diff --git a/ocaml/num.ml.ar b/ocaml/num.ml.ar
new file mode 100644 (file)
index 0000000..6a11731
--- /dev/null
@@ -0,0 +1,294 @@
+open Util
+open Util.Vars
+open Pure
+
+(************ Syntax ************************************)
+
+(* Normal forms*)
+
+(* Var n = n-th De Bruijn index, 0-based *)
+
+(*type nf =
+  | Lam of nf
+  | Var of int
+  | i
+and i =
+  | I of int * nf listx
+;;*)
+type 'nf i_var_ = [ `I of int * int * 'nf Listx.listx | `Var of int * int ]
+type 'nf i_n_var_ = [ `N of int | 'nf i_var_ ]
+type 'nf i_num_var_ = [
+  | 'nf i_n_var_
+  | `Match of int * 'nf i_num_var_ * (*lift*) int * (*branches*)(int * 'nf) list ref * (*args*)'nf list
+]
+type 'nf nf_ = [ `Lam of (* was_unpacked *) bool * 'nf nf_ | 'nf i_num_var_ ]
+type nf = nf nf_
+type i_var = nf i_var_;;
+type i_n_var = nf i_n_var_;;
+type i_num_var = nf i_num_var_;;
+
+let hd_of_i_var =
+ function
+   `I (_,v,_)
+ | `Var (_,v) -> v
+
+let hd_of =
+ function
+   `I (_,v,_)
+ | `Var (_,v) -> Some v
+ | `N _ -> None
+ | `Match _ -> assert false
+
+let lift m (t : nf) =
+ let rec aux_i_num_var l =
+  function
+    `I(ar,n,args) -> (`I(ar,(if n < l then n else n+m),Listx.map (aux l) args) : i_num_var)
+   | `Var (ar,n) -> `Var (ar, if n < l then n else n+m)
+   | `N _ as x -> x
+   | `Match(ar,t,lift,bs,args) ->
+      `Match(ar,aux_i_num_var l t, lift + m, bs, List.map (aux l) args)
+ and aux l =
+  function
+     #i_num_var as x -> (aux_i_num_var l x :> nf)
+   | `Lam(b,nf) -> `Lam (b,aux (l+1) nf)
+ in
+  (aux 0 t : nf)
+;;
+
+(* put t under n lambdas, lifting t accordingtly *)
+let rec make_lams t =
+ function
+   0 -> t
+ | n when n > 0 -> `Lam (false,lift 1 (make_lams t (n-1)))
+ | _ -> assert false
+
+let free_vars =
+ let rec aux n = function
+    `N _ -> []
+  | `Var (_,x) -> if x < n then [] else [x-n]
+  | `I(_,x,args) ->
+      (if x < n then [] else [x-n]) @
+      List.concat (List.map (aux n) (Listx.to_list args))
+  | `Lam(_,t) -> aux (n+1) t
+  | `Match(_,t,liftno,bs,args) ->
+      aux n (t :> nf) @
+      List.concat (List.map (fun (_,t) -> aux (n-liftno) t) !bs) @
+      List.concat (List.map (aux n) args)
+  in aux 0
+;;
+
+module ToScott =
+struct
+
+let rec t_of_i_num_var =
+ function
+  | `N n -> Scott.mk_n n
+  | `Var (_,v) -> Pure.V v
+  | `Match(_,t,liftno,bs,args) ->
+      let bs = List.map (fun (n,t) -> n, t_of_nf (lift liftno t)) !bs in
+      let t = t_of_i_num_var t in
+      let m = Scott.mk_match t bs in
+      List.fold_left (fun acc t -> Pure.A(acc,t_of_nf t)) m args
+  | `I(_,v, args) -> Listx.fold_left (fun acc t -> Pure.A(acc,t_of_nf t)) (Pure.V v) args
+and t_of_nf =
+ function
+  | #i_num_var as x -> t_of_i_num_var x
+  | `Lam(b,f) -> Pure.L (t_of_nf f)
+
+end
+
+
+(************ Pretty-printing ************************************)
+
+let rec print ?(l=[]) =
+ function
+    `Var (_,n) -> print_name l n
+  | `N n -> string_of_int n
+  | `Match(_,t,bs_lift,bs,args) ->
+     "([" ^ print ~l (t :> nf) ^
+     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (lift bs_lift t)) !bs) ^ "] " ^
+     String.concat " " (List.map (print ~l) args) ^ ")"
+  | `I(_,n,args) -> "(" ^ print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"
+  | `Lam(_,nf) ->
+     let name = string_of_var (List.length l) in
+     "λ" ^ name ^ "." ^ print ~l:(name::l) (nf : nf)
+;;
+
+let rec string_of_term l =
+ let rec string_of_term_w_pars l = function
+  | `Var (_,n) -> print_name l n
+  | `N n -> string_of_int n
+  | `I _ as t -> "(" ^ string_of_term_no_pars_app l (t :> nf) ^ ")"
+  | `Lam _ as t -> "(" ^ string_of_term_no_pars_lam l t ^ ")"
+  | `Match(_,t,bs_lift,bs,args) ->
+     "(match " ^ string_of_term_no_pars l (t :> nf) ^
+     " with " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ string_of_term l (lift bs_lift t)) !bs) ^ "] " ^
+     String.concat " " (List.map (string_of_term l) args) ^ ")"
+ and string_of_term_no_pars_app l = function
+  | `I(_,n, args) -> print_name l n ^ " " ^ String.concat " " (List.map (string_of_term_w_pars l) (Listx.to_list args))
+  | #nf as t -> string_of_term_w_pars l t
+ and string_of_term_no_pars_lam l  = function
+  | `Lam(_,t) -> let name = string_of_var (List.length l) in
+   "λ" ^ name ^ ". " ^ (string_of_term_no_pars_lam (name::l) t)
+  | _ as t -> string_of_term_no_pars l t
+ and string_of_term_no_pars l : nf -> string = function
+  | `Lam _ as t -> string_of_term_no_pars_lam l t
+  | #nf as t -> string_of_term_no_pars_app l t
+ in string_of_term_no_pars l
+;;
+
+let print ?(l=[]) = string_of_term l;;
+let string_of_nf t = string_of_term [] (t:>nf);;
+
+(************ Hereditary substitutions ************************************)
+
+let cast_to_i_var =
+ function
+    #i_var as y -> (y : i_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let cast_to_i_n_var =
+ function
+    #i_n_var as y -> (y : i_n_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let cast_to_i_num_var =
+ function
+    #i_num_var as y -> (y : i_num_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let rec mk_app (h : nf) (arg : nf) =
+(*let res =*)
+ match h with
+    `I(ar,n,args) -> `I(ar,n,Listx.append (Listx.Nil arg) args)
+  | `Var (ar,n) -> `I(ar,n, Listx.Nil arg)
+  | `Lam(_,nf) -> subst true 0 arg (nf : nf)
+  | `Match(ar,t,lift,bs,args) -> `Match(ar,t,lift,bs,List.append args [arg])
+  | `N _ -> assert false (* Numbers cannot be applied *)
+(*in let l = ["v0";"v1";"v2"] in
+prerr_endline ("mk_app h:" ^ print ~l h ^ " arg:" ^ print ~l:l arg ^ " res:" ^ print ~l:l res); res*)
+
+and mk_appl h args =
+ (*prerr_endline ("MK_APPL: " ^ print h ^ " " ^ String.concat " " (List.map print args));*)
+ List.fold_left mk_app h args
+
+and mk_appx h args = Listx.fold_left mk_app h args
+
+and mk_match ar t bs_lift bs args =
+ (*prerr_endline ("MK_MATCH: ([" ^ print t ^ "] " ^ String.concat " " (Listx.to_list (Listx.map (fun (n,t) -> string_of_int n ^ " => " ^ print t) bs)) ^ ") " ^ String.concat " " (List.map print args));*)
+ match t with
+    `N m ->
+      (try
+        let h = List.assoc m !bs in
+        let h = lift bs_lift h in
+        mk_appl h args
+       with Not_found ->
+        `Match (ar,t,bs_lift,bs,args))
+  | `I _ | `Var _ | `Match _ -> `Match(ar,t,bs_lift,bs,args)
+
+and subst delift_by_one what (with_what : nf) (where : nf) =
+ let rec aux_i_num_var l =
+  function
+     `I(ar,n,args) ->
+       if n = what + l then
+        mk_appx (lift l with_what) (Listx.map (aux l) args)
+       else
+        `I (ar,(if delift_by_one && n >= l then n-1 else n), Listx.map (aux l) args)
+   | `Var (ar,n) ->
+       if n = what + l then
+        lift l with_what
+       else
+        `Var (ar,if delift_by_one && n >= l then n-1 else n)
+   | `N _ as x -> x
+   | `Match(ar,t,bs_lift,bs,args) ->
+       let bs_lift = bs_lift + if delift_by_one then -1 else 0 in
+       let l' = l - bs_lift  in
+       let with_what' = lift l' with_what in
+       (* The following line should be the identity when delift_by_one = true because we
+          are assuming the ts to not contain lambda-bound variables. *)
+       bs := List.map (fun (n,t) -> n,subst false what with_what' t) !bs ;
+       mk_match ar (cast_to_i_num_var (aux_i_num_var l t)) bs_lift bs (List.map (aux l) args)
+ and aux l(*lift*) =
+(*function iii -> let res = match iii with*)
+  function
+   | #i_num_var as x -> aux_i_num_var l x
+   | `Lam(b,nf) -> `Lam(b,aux (l+1) nf)
+(*in let ll = ["v0";"v1";"v2"] in
+prerr_endline ("subst l:" ^ string_of_int l ^ " delift_by_one:" ^ string_of_bool delift_by_one ^ " what:" ^ (List.nth ll what) ^ " with_what:" ^ print ~l:ll with_what ^ " where:" ^ print ~l:ll iii ^ " res:" ^ print ~l:ll res); res*)
+ in
+  aux 0 where
+;;
+
+(************ Parsing ************************************)
+
+let parse' strs =
+  let rec aux = function
+  | Parser.Lam t -> `Lam (true,aux t)
+  | Parser.App (t1, t2) -> mk_app (aux t1) (aux t2)
+  | Parser.Var v -> `Var (-1,v)
+  in let (tms, free) = Parser.parse_many strs
+  in (List.map aux tms, free)
+;;
+
+(************** Algorithm(s) ************************)
+
+let eta_compare x y =
+ (* let clex a b = let diff = ? a b in if diff = 0 then cont () else 0 in *)
+ let clex aux1 aux2 (a1,a2) (b1,b2) =
+  let diff = aux1 a1 b1 in if diff = 0 then aux2 a2 b2 else diff in
+ let rec lex aux l1 l2 =
+  match l1,l2 with
+ | [], [] -> 0
+ | [], _ -> -1
+ | _, [] -> 1
+ | x::xs, y::ys -> clex aux (lex aux) (x,xs) (y,ys) in
+ let rec aux t1 t2 = match t1, t2 with
+  | `Var (_,n) , `Var (_,m) -> compare n m
+  | `I(_, n1, l1), `I(_, n2, l2) ->
+    clex compare (lex aux) (n1, Listx.to_list l1) (n2, Listx.to_list l2)
+  | `Lam _, `N _ -> -1
+  | `N _, `Lam _ -> 1
+  | `Lam(_,t1), `Lam(_,t2) -> aux t1 t2
+  | `Lam(_,t1), t2 -> - aux t1 (mk_app (lift 1 t2) (`Var (-1,0)))
+  | t2, `Lam(_,t1) ->   aux t1 (mk_app (lift 1 t2) (`Var (-1,0)))
+  | `N n1, `N n2 -> compare n1 n2
+  | `Match(_,u,bs_lift,bs,args), `Match(_,u',bs_lift',bs',args') ->
+    let bs = List.sort (fun (n,_) (m,_) -> compare n m) !bs in
+    let bs' = List.sort (fun (n,_) (m,_) -> compare n m) !bs' in
+    clex aux (clex (lex (clex compare aux)) (lex aux)) ((u :> nf), (bs, args)) ((u' :> nf), (bs', args'))
+  | `Match _, _ -> -1
+  | _, `Match _ -> 1
+  | `N _, _ -> -1
+  | _, `N _ -> 1
+  | `I _, _ -> -1
+  | _, `I _ -> 1
+  in aux x y
+;;
+
+let eta_eq (#nf as x) (#nf as y) = 0 = eta_compare x y ;;
+
+let rec eta_subterm sub t =
+ if eta_eq sub t then true else
+  match t with
+  | `Lam(_,t') -> eta_subterm (lift 1 sub) t'
+  | `Match(_,u,liftno,bs,args) ->
+     eta_subterm sub (u :> nf)
+     || List.exists (fun (_, t) -> eta_subterm sub (lift liftno t)) !bs
+     || List.exists (eta_subterm sub) args
+  | `I(_, v, args) -> List.exists (eta_subterm sub) (Listx.to_list args) || (match sub with
+   | `Var (_,v') -> v = v'
+   | `I(_, v', args') -> v = v'
+    && Listx.length args' < Listx.length args
+    && List.for_all (fun (x,y) -> eta_eq x y) (List.combine (Util.take (Listx.length args') (Listx.to_list args)) (Listx.to_list args'))
+   | _ -> false
+   )
+  | `N _ | `Var _ -> false
+;;
+
+let eta_subterm (#nf as x) (#nf as y) = eta_subterm x y;;
diff --git a/ocaml/num.mli b/ocaml/num.mli
new file mode 100644 (file)
index 0000000..2f92884
--- /dev/null
@@ -0,0 +1,43 @@
+type 'nf i_var_ = [ `I of int * 'nf Listx.listx | `Var of int ]
+type 'nf i_n_var_ = [ `N of int | 'nf i_var_ ]
+type 'nf i_num_var_ =
+    [ `I of int * 'nf Listx.listx
+    | `Match of 'nf i_num_var_ * int * (int * 'nf) list ref * 'nf list
+    | `N of int
+    | `Var of int ]
+type 'nf nf_ =
+    [ `I of int * 'nf Listx.listx
+    | `Lam of bool * 'nf nf_
+    | `Match of 'nf i_num_var_ * int * (int * 'nf) list ref * 'nf list
+    | `N of int
+    | `Var of int ]
+type nf = nf nf_
+type i_var = nf i_var_
+type i_n_var = nf i_n_var_
+type i_num_var = nf i_num_var_
+val hd_of_i_var : i_var -> int
+val hd_of :
+  [< `I of 'a * 'b | `Match of 'c | `N of 'd | `Var of 'a ] -> 'a option
+(* put t under n lambdas, lifting t accordingtly *)
+val make_lams : nf -> int -> nf
+val lift : int -> nf -> nf
+val free_vars : nf -> int list
+module ToScott :
+  sig
+    val t_of_i_num_var : nf i_num_var_ -> Pure.Pure.t
+    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
+val mk_app : nf -> nf -> nf
+val mk_appl : nf -> nf list -> nf
+val mk_appx : nf -> nf Listx.listx -> nf
+val mk_match : nf i_num_var_ -> int -> (int * nf) list ref -> nf list -> nf
+val subst : bool -> int -> nf -> nf -> nf
+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
diff --git a/ocaml/num.mli.ar b/ocaml/num.mli.ar
new file mode 100644 (file)
index 0000000..46bf51e
--- /dev/null
@@ -0,0 +1,43 @@
+type 'nf i_var_ = [ `I of int * int * 'nf Listx.listx | `Var of int * int ]
+type 'nf i_n_var_ = [ `N of int | 'nf i_var_ ]
+type 'nf i_num_var_ =
+    [ `I of int * int * 'nf Listx.listx
+    | `Match of int * 'nf i_num_var_ * int * (int * 'nf) list ref * 'nf list
+    | `N of int
+    | `Var of int * int ]
+type 'nf nf_ =
+    [ `I of int * int * 'nf Listx.listx
+    | `Lam of bool * 'nf nf_
+    | `Match of int * 'nf i_num_var_ * int * (int * 'nf) list ref * 'nf list
+    | `N of int
+    | `Var of int * int ]
+type nf = nf nf_
+type i_var = nf i_var_
+type i_n_var = nf i_n_var_
+type i_num_var = nf i_num_var_
+val hd_of_i_var : i_var -> int
+val hd_of :
+  [< `I of 'c * 'a * 'b | `Match of 'c | `N of 'd | `Var of 'e * 'a ] -> 'a option
+(* put t under n lambdas, lifting t accordingtly *)
+val make_lams : nf -> int -> nf
+val lift : int -> nf -> nf
+val free_vars : nf -> int list
+module ToScott :
+  sig
+    val t_of_i_num_var : nf i_num_var_ -> Pure.Pure.t
+    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
+val mk_app : nf -> nf -> nf
+val mk_appl : nf -> nf list -> nf
+val mk_appx : nf -> nf Listx.listx -> nf
+val mk_match : int -> nf i_num_var_ -> int -> (int * nf) list ref -> nf list -> nf
+val subst : bool -> int -> nf -> nf -> nf
+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
diff --git a/ocaml/numx.ml b/ocaml/numx.ml
new file mode 100644 (file)
index 0000000..b958ed5
--- /dev/null
@@ -0,0 +1,294 @@
+open Util
+open Util.Vars
+open Pure
+
+(************ Syntax ************************************)
+
+(* Normal forms*)
+
+(* Var n = n-th De Bruijn index, 0-based *)
+
+(*type nf =
+  | Lam of nf
+  | Var of int
+  | i
+and i =
+  | I of int * nf listx
+;;*)
+type 'nf i_var_ = [ `I of int * 'nf Listx.listx | `Var of int ]
+type 'nf i_n_var_ = [ `N of int | 'nf i_var_ ]
+type 'nf i_num_var_ = [
+  | 'nf i_n_var_
+  | `Match of 'nf i_num_var_ * (*lift*) int * (*branches*)(int * 'nf) list ref * (*args*)'nf list
+]
+type 'nf nf_ = [ `Lam of (* was_unpacked *) bool * 'nf nf_ | `Bomb | `Pacman | 'nf i_num_var_ ]
+type nf = nf nf_
+type i_var = nf i_var_;;
+type i_n_var = nf i_n_var_;;
+type i_num_var = nf i_num_var_;;
+
+let hd_of_i_var =
+ function
+   `I (v,_)
+ | `Var v -> v
+
+let hd_of =
+ function
+   `I (v,_)
+ | `Var v -> Some v
+ | `N _ -> None
+ | `Match _ | `Bomb -> assert false
+
+let lift m (t : nf) =
+ let rec aux_i_num_var l =
+  function
+    `I(n,args) -> (`I((if n < l then n else n+m),Listx.map (aux l) args) : i_num_var)
+   | `Var n -> `Var (if n < l then n else n+m)
+   | `N _ as x -> x
+   | `Match(t,lift,bs,args) ->
+      `Match(aux_i_num_var l t, lift + m, bs, List.map (aux l) args)
+ and aux l =
+  function
+     #i_num_var as x -> (aux_i_num_var l x :> nf)
+   | `Lam(b,nf) -> `Lam (b,aux (l+1) nf)
+   | `Bomb -> `Bomb
+   | `Pacman -> `Pacman
+ in
+  (aux 0 t : nf)
+;;
+
+(* put t under n lambdas, lifting t accordingtly *)
+let rec make_lams t =
+ function
+   0 -> t
+ | n when n > 0 -> `Lam (false,lift 1 (make_lams t (n-1)))
+ | _ -> assert false
+
+let free_vars =
+ let rec aux n = function
+    `N _ -> []
+  | `Var x -> if x < n then [] else [x-n]
+  | `I(x,args) ->
+      (if x < n then [] else [x-n]) @
+      List.concat (List.map (aux n) (Listx.to_list args))
+  | `Lam(_,t) -> aux (n+1) t
+  | `Match(t,liftno,bs,args) ->
+      aux n (t :> nf) @
+      List.concat (List.map (fun (_,t) -> aux (n-liftno) t) !bs) @
+      List.concat (List.map (aux n) args)
+  | `Bomb | `Pacman -> []
+  in aux 0
+;;
+
+module ToScott =
+struct
+
+let rec t_of_i_num_var =
+ function
+  | `N n -> Scott.mk_n n
+  | `Var v -> Pure.V v
+  | `Match(t,liftno,bs,args) ->
+      let bs = List.map (fun (n,t) -> n, t_of_nf (lift liftno t)) !bs in
+      let t = t_of_i_num_var t in
+      let m = Scott.mk_match t bs in
+      List.fold_left (fun acc t -> Pure.A(acc,t_of_nf t)) m args
+  | `I(v, args) -> Listx.fold_left (fun acc t -> Pure.A(acc,t_of_nf t)) (Pure.V v) args
+and t_of_nf =
+ function
+  | #i_num_var as x -> t_of_i_num_var x
+  | `Lam(b,f) -> Pure.L (t_of_nf f)
+  | `Bomb -> let f x = Pure.A (x,x) in f (Pure.L (f (Pure.V 0)))
+  | `Pacman -> let f x = Pure.A (x,x) in f (Pure.L (Pure.L (f (Pure.V 0))))
+
+end
+
+
+(************ Pretty-printing ************************************)
+
+(* let rec print ?(l=[]) =
+ function
+    `Var n -> print_name l n
+  | `N n -> string_of_int n
+  | `Match(t,bs_lift,bs,args) ->
+     "([" ^ print ~l (t :> nf) ^
+     " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (lift bs_lift t)) !bs) ^ "] " ^
+     String.concat " " (List.map (print ~l) args) ^ ")"
+  | `I(n,args) -> "(" ^ print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"
+  | `Lam(_,nf) ->
+     let name = string_of_var (List.length l) in
+     "λ" ^ name ^ "." ^ print ~l:(name::l) (nf : nf)
+;; *)
+
+let rec string_of_term l =
+ let rec string_of_term_w_pars l = function
+  | `Var n -> print_name l n
+  | `N n -> string_of_int n
+  | `I _ as t -> "(" ^ string_of_term_no_pars_app l (t :> nf) ^ ")"
+  | `Lam _ as t -> "(" ^ string_of_term_no_pars_lam l t ^ ")"
+  | `Match(t,bs_lift,bs,args) ->
+     "(match " ^ string_of_term_no_pars l (t :> nf) ^
+     " with " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ string_of_term l (lift bs_lift t)) !bs) ^ "] " ^
+     String.concat " " (List.map (string_of_term l) args) ^ ")"
+  | `Bomb -> "TNT"
+  | `Pacman -> "PAC"
+ and string_of_term_no_pars_app l = function
+  | `I(n, args) -> print_name l n ^ " " ^ String.concat " " (List.map (string_of_term_w_pars l) (Listx.to_list args))
+  | #nf as t -> string_of_term_w_pars l t
+ and string_of_term_no_pars_lam l  = function
+  | `Lam(_,t) -> let name = string_of_var (List.length l) in
+   "λ" ^ name ^ ". " ^ (string_of_term_no_pars_lam (name::l) t)
+  | _ as t -> string_of_term_no_pars l t
+ and string_of_term_no_pars l : nf -> string = function
+  | `Lam _ as t -> string_of_term_no_pars_lam l t
+  | #nf as t -> string_of_term_no_pars_app l t
+ in string_of_term_no_pars l
+;;
+
+let rec print ?(l=[]) = string_of_term l;;
+
+(************ Hereditary substitutions ************************************)
+
+let cast_to_i_var =
+ function
+    #i_var as y -> (y : i_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let cast_to_i_n_var =
+ function
+    #i_n_var as y -> (y : i_n_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let cast_to_i_num_var =
+ function
+    #i_num_var as y -> (y : i_num_var)
+  | t ->
+    prerr_endline (print (t :> nf));
+    assert false (* algorithm failed *)
+
+let rec mk_app (h : nf) (arg : nf) =
+(*let res =*)
+ match h with
+    `I(n,args) -> `I(n,Listx.append (Listx.Nil arg) args)
+  | `Var n -> `I(n, Listx.Nil arg)
+  | `Lam(_,nf) -> subst true 0 arg (nf : nf)
+  | `Match(t,lift,bs,args) -> `Match(t,lift,bs,List.append args [arg])
+  | `N _ -> assert false (* Numbers cannot be applied *)
+  | `Bomb | `Pacman -> failwith "mk_app su bomba o pacman"
+(*in let l = ["v0";"v1";"v2"] in
+prerr_endline ("mk_app h:" ^ print ~l h ^ " arg:" ^ print ~l:l arg ^ " res:" ^ print ~l:l res); res*)
+
+and mk_appl h args =
+ (*prerr_endline ("MK_APPL: " ^ print h ^ " " ^ String.concat " " (List.map print args));*)
+ List.fold_left mk_app h args
+
+and mk_appx h args = Listx.fold_left mk_app h args
+
+and mk_match t bs_lift bs args =
+ (*prerr_endline ("MK_MATCH: ([" ^ print t ^ "] " ^ String.concat " " (Listx.to_list (Listx.map (fun (n,t) -> string_of_int n ^ " => " ^ print t) bs)) ^ ") " ^ String.concat " " (List.map print args));*)
+ match t with
+    `N m ->
+      (try
+        let h = List.assoc m !bs in
+        let h = lift bs_lift h in
+        mk_appl h args
+       with Not_found ->
+        `Match (t,bs_lift,bs,args))
+  | `I _ | `Var _ | `Match _ -> `Match(t,bs_lift,bs,args)
+
+and subst delift_by_one what (with_what : nf) (where : nf) =
+ let rec aux_i_num_var l =
+  function
+     `I(n,args) ->
+       if n = what + l then
+        mk_appx (lift l with_what) (Listx.map (aux l) args)
+       else
+        `I ((if delift_by_one && n >= l then n-1 else n), Listx.map (aux l) args)
+   | `Var n ->
+       if n = what + l then
+        lift l with_what
+       else
+        `Var (if delift_by_one && n >= l then n-1 else n)
+   | `N _ as x -> x
+   | `Match(t,bs_lift,bs,args) ->
+       let bs_lift = bs_lift + if delift_by_one then -1 else 0 in
+       let l' = l - bs_lift  in
+       let with_what' = lift l' with_what in
+       (* The following line should be the identity when delift_by_one = true because we
+          are assuming the ts to not contain lambda-bound variables. *)
+       bs := List.map (fun (n,t) -> n,subst false what with_what' t) !bs ;
+       mk_match (cast_to_i_num_var (aux_i_num_var l t)) bs_lift bs (List.map (aux l) args)
+ and aux l(*lift*) =
+(*function iii -> let res = match iii with*)
+  function
+   | #i_num_var as x -> aux_i_num_var l x
+   | `Lam(b,nf) -> `Lam(b,aux (l+1) nf)
+   | `Bomb -> `Bomb
+   | `Pacman -> `Pacman
+(*in let ll = ["v0";"v1";"v2"] in
+prerr_endline ("subst l:" ^ string_of_int l ^ " delift_by_one:" ^ string_of_bool delift_by_one ^ " what:" ^ (List.nth ll what) ^ " with_what:" ^ print ~l:ll with_what ^ " where:" ^ print ~l:ll iii ^ " res:" ^ print ~l:ll res); res*)
+ in
+  aux 0 where
+;;
+
+(************ Parsing ************************************)
+
+let parse' strs =
+  let rec aux = function
+  | Parser.Lam t -> `Lam (true,aux t)
+  | Parser.App (t1, t2) -> mk_app (aux t1) (aux t2)
+  | Parser.Var v -> `Var v
+  in let (tms, free) = Parser.parse_many strs
+  in (List.map aux tms, free)
+;;
+
+(************** Algorithm(s) ************************)
+
+let eta_eq x y =
+  let rec aux = function
+  | `Var n , `Var m -> n = m
+  | `I(n1, l1), `I(n2, l2) ->
+    n1 = n2 && Listx.length l1 = Listx.length l2 &&
+    List.for_all aux (List.combine (Listx.to_list l1) (Listx.to_list l2))
+  | `Lam(_,t1), `Lam(_,t2) -> aux (t1,t2)
+  | `Lam(_,t1), t2
+  | t2, `Lam(_,t1) -> aux( t1,  (mk_app (lift 1 t2) (`Var 0)) )
+  | `N n1, `N n2 -> n1 = n2
+  | `Match(u,bs_lift,bs,args), `Match(u',bs_lift',bs',args') ->
+    aux ((u :> nf), (u' :> nf)) && List.length !bs = List.length !bs' &&
+    let bs = List.sort (fun (n,_) (m,_) -> compare n m) !bs in
+    let bs' = List.sort (fun (n,_) (m,_) -> compare n m) !bs' in
+    List.for_all (fun ((n,t),(n',t')) -> n = n' && aux (t, t')) (List.combine bs bs') && List.length args = List.length args' &&
+    List.for_all aux (List.combine args args')
+  | _ -> false
+  in aux (x, y)
+;;
+
+let eta_compare x y =
+  if eta_eq x y then 0 else compare x y
+;;
+
+let eta_eq (#nf as x) (#nf as y) = eta_eq x y;;
+
+let rec eta_subterm sub t =
+ if eta_eq sub t then true else
+  match t with
+  | `Lam(_,t') -> eta_subterm (lift 1 sub) t'
+  | `Match(u,liftno,bs,args) ->
+     eta_subterm sub (u :> nf)
+     || List.exists (fun (_, t) -> eta_subterm sub (lift liftno t)) !bs
+     || List.exists (eta_subterm sub) args
+  | `I(v, args) -> List.exists (eta_subterm sub) (Listx.to_list args) || (match sub with
+   | `Var v' -> v = v'
+   | `I(v', args') -> v = v'
+    && Listx.length args' < Listx.length args
+    && List.for_all (fun (x,y) -> eta_eq x y) (List.combine (Util.take (Listx.length args') (Listx.to_list args)) (Listx.to_list args'))
+   | _ -> false
+   )
+  | `N _ | `Var _ | `Bomb | `Pacman -> false
+;;
+
+let eta_subterm (#nf as x) (#nf as y) = eta_subterm x y;;
diff --git a/ocaml/numx.mli b/ocaml/numx.mli
new file mode 100644 (file)
index 0000000..206c32f
--- /dev/null
@@ -0,0 +1,44 @@
+type 'nf i_var_ = [ `I of int * 'nf Listx.listx | `Var of int ]
+type 'nf i_n_var_ = [ `N of int | 'nf i_var_ ]
+type 'nf i_num_var_ =
+    [ `I of int * 'nf Listx.listx
+    | `Match of 'nf i_num_var_ * int * (int * 'nf) list ref * 'nf list
+    | `N of int
+    | `Var of int ]
+type 'nf nf_ =
+    [ `I of int * 'nf Listx.listx
+    | `Lam of bool * 'nf nf_
+    | `Match of 'nf i_num_var_ * int * (int * 'nf) list ref * 'nf list
+    | `N of int
+    | `Var of int
+    | `Bomb
+    | `Pacman ]
+type nf = nf nf_
+type i_var = nf i_var_
+type i_n_var = nf i_n_var_
+type i_num_var = nf i_num_var_
+val hd_of_i_var : i_var -> int
+val hd_of :
+  [< `I of 'a * 'b | `Match of 'c | `N of 'd | `Var of 'a ] -> 'a option
+(* put t under n lambdas, lifting t accordingtly *)
+val make_lams : nf -> int -> nf
+val lift : int -> nf -> nf
+val free_vars : nf -> int list
+module ToScott :
+  sig
+    val t_of_i_num_var : nf i_num_var_ -> Pure.Pure.t
+    val t_of_nf : nf -> Pure.Pure.t
+  end
+val print : ?l:string list -> 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
+val mk_app : nf -> nf -> nf
+val mk_appl : nf -> nf list -> nf
+val mk_appx : nf -> nf Listx.listx -> nf
+val mk_match : nf i_num_var_ -> int -> (int * nf) list ref -> nf list -> nf
+val subst : bool -> int -> nf -> nf -> nf
+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
diff --git a/ocaml/parser.ml b/ocaml/parser.ml
new file mode 100644 (file)
index 0000000..4c7b829
--- /dev/null
@@ -0,0 +1,153 @@
+type term =\r
+  | Var of int\r
+  | App of term * term\r
+  | Lam of term\r
+;;\r
+\r
+let mk_app x y = App(x, y);;\r
+let mk_lam x = Lam x;;\r
+let mk_var x = Var x;;\r
+\r
+exception ParsingError of string;;\r
+\r
+let isAlphaNum c = let n = Char.code c in 48 <= n && n <= 122 ;;\r
+let isSpace c = c = ' ' || c = '\n' || c = '\t' ;;\r
+\r
+let rec index_of x =\r
+  function\r
+  | [] -> raise (Failure "index_of: Not Found")\r
+  | h::t -> if x = h then 0 else 1 + index_of x t\r
+;;\r
+(* FIXME *)\r
+let mk_var' (bound, free) x =\r
+  if List.mem x bound\r
+  then free, mk_var (index_of x bound)\r
+  else if List.mem x free\r
+       then free, mk_var (List.length bound + index_of x free)\r
+       else (free @ [x]), mk_var (List.length bound + List.length free)\r
+;;\r
+\r
+let mk_app' = function\r
+  | [] ->  raise (ParsingError "bug")\r
+  | t :: ts -> List.fold_left mk_app t ts\r
+;;\r
+\r
+let explode s =\r
+  let rec aux i l =\r
+    if i < 0 then l else aux (i - 1) (s.[i] :: l)\r
+  in aux (String.length s - 1) []\r
+;;\r
+\r
+let implode l =\r
+  let res = String.create (List.length l) in\r
+  let rec aux i = function\r
+    | [] -> res\r
+    | c :: l -> res.[i] <- c; aux (i + 1) l in\r
+  aux 0 l\r
+;;\r
+\r
+let rec strip_spaces = function\r
+  | c::cs when isSpace c -> strip_spaces cs\r
+  | cs -> cs\r
+;;\r
+\r
+let read_var s =\r
+  let rec aux = function\r
+  | [] -> None, []\r
+  | c::cs as x -> if isAlphaNum c\r
+    then match aux cs with\r
+         | (Some x), cs' -> Some (c :: x), cs'\r
+         | None, cs' -> (Some [c]), cs'\r
+    else None, x\r
+  in match aux s with\r
+    | None, y -> None, y\r
+    | Some x, y -> Some (implode x), y\r
+;;\r
+\r
+let read_var' (bound, free as vars) s =\r
+  match read_var s with\r
+  | Some varname, cs ->\r
+    let free, v = mk_var' vars varname in\r
+    Some [v], cs, (bound, free)\r
+  | _, _ -> raise (ParsingError ("Can't read variable"))\r
+;;\r
+\r
+let rec read_smt vars =\r
+  let check_if_lambda cs = match read_var cs with\r
+    | None, _ -> false\r
+    | Some x, cs -> match strip_spaces cs with\r
+      | [] -> false\r
+      | c::_ -> c = '.'\r
+  in let read_lambda (bound, free) cs = (\r
+    match read_var (strip_spaces cs) with\r
+      | Some varname, cs ->\r
+      let vars' = (varname::bound, free) in\r
+      (match strip_spaces cs with\r
+        | [] -> raise (ParsingError "manca dopo variabile lambda")\r
+        | c::cs -> (if c = '.' then (match read_smt vars' cs with\r
+          | None, _, _ -> raise (ParsingError "manca corpo lambda")\r
+          | Some [x], y, (_, free) -> Some [mk_lam x], y, (bound, free)\r
+          | Some _, _, _ -> raise (ParsingError "???")\r
+          ) else raise (ParsingError "manca . nel lambda")\r
+        ))\r
+      | _, _ -> assert false\r
+ ) in let rec aux vars cs =\r
+  match strip_spaces cs with\r
+  | [] -> None, [], vars\r
+  | c::_ as x ->\r
+      let tms, cs, vars = (\r
+           if c = '(' then read_pars vars x\r
+      else if c = ')' then (None, x, vars)\r
+      else if check_if_lambda x then read_lambda vars x\r
+      else read_var' vars x) in\r
+      match tms with\r
+      | Some [tm] -> (\r
+        match aux vars cs with\r
+          | None, cs, vars -> Some [tm], cs, vars\r
+          | Some ts, cs, vars -> Some (tm :: ts), cs, vars\r
+        )\r
+      | Some _ -> raise (ParsingError "bug")\r
+      | None -> None, x, vars\r
+  in fun cs -> match aux vars cs with\r
+    | None, cs, vars -> None, cs, vars\r
+    | Some ts, cs, vars -> Some [mk_app' ts], cs, vars\r
+and read_pars vars = function\r
+  | [] -> None, [], vars\r
+  | c::cs -> if c = '(' then (\r
+    let tm, cs, vars = read_smt vars cs in\r
+    let cs = strip_spaces cs in\r
+    match cs with\r
+      | [] -> None, [], vars\r
+      | c::cs -> if c = ')' then tm, cs, vars else raise (ParsingError ") mancante")\r
+    ) else raise (ParsingError "???")\r
+;;\r
+\r
+let parse x =\r
+  match read_smt ([],[]) (explode x) with\r
+  | Some [y], [], _ -> y\r
+  | _, _, _ -> raise (ParsingError "???")\r
+;;\r
+\r
+let var_zero = "ω";; (* w is an invalid variable name *)\r
+\r
+let parse_many strs =\r
+  let f (x, y) z = match read_smt y (explode z) with\r
+  | Some[tm], [], vars -> (tm :: x, vars)\r
+  | _, _, _ -> raise (ParsingError "???")\r
+  in let aux = List.fold_left f ([], ([], [var_zero])) (* index zero is reserved *)\r
+  in let (tms, (_, free)) = aux strs\r
+  in (List.rev tms, free)\r
+;;\r
+\r
+(**********************************************************************\r
+\r
+let rec string_of_term = function\r
+  | Tvar n -> string_of_int n\r
+  | Tapp(t1, t2) -> "(" ^ string_of_term t1 ^ " " ^ string_of_term t2 ^ ")"\r
+  | Tlam(t1) -> "(\\" ^ string_of_term t1 ^ ")"\r
+;;\r
+\r
+let _ = prerr_endline (">>>" ^ string_of_term (parse "(\\x. x y z z1 k) z1 z j"));;\r
+\r
+\r
+**********************************************************************)\r
diff --git a/ocaml/parser.mli b/ocaml/parser.mli
new file mode 100644 (file)
index 0000000..c073c3a
--- /dev/null
@@ -0,0 +1,9 @@
+type term =\r
+  | Var of int\r
+  | App of term * term\r
+  | Lam of term\r
+\r
+(* parses a string to a term *)\r
+val parse: string -> term\r
+(* parse many strings/terms, and returns the list of parsed terms + the list of free variables; variable 0 is not used *)\r
+val parse_many: string list -> term list * string list\r
diff --git a/ocaml/problems.ml b/ocaml/problems.ml
new file mode 100644 (file)
index 0000000..6fb7b43
--- /dev/null
@@ -0,0 +1,304 @@
+let use_lambda3 = Array.length Sys.argv = 1;;
+
+let discriminator =
+ if use_lambda3 then (module Lambda3 : Discriminator.Discriminator) else (module Lambda4);;
+module Pippo = (val discriminator);;
+open Pippo;;
+
+let p2 = magic [ "x y"; "x z" ; "x (y z)"] ["*"]
+
+let p4 = magic
+  [ "x y"; "x (a. a x)" ; "y (y z)" ] ["*"]
+
+let p5 = magic
+  ["a (x. x a) b"; "b (x. x b) a"]
+  ["*"]
+;;
+
+let p6 = magic
+  ["a (x. x a) b"; "b (x. x b) (c a)"]
+  ["*"]
+;;
+
+let p7 = magic
+  ["a (x. (x a)(a x x a)(x x) )"]
+  ["*"]
+;;
+
+let p8 = magic
+  ["x x (x x)"]
+  ["*"]
+;;
+
+let p9 = magic
+  ["x x (x x x) (x x (x x)) (x x (x x x)) x x"]
+  ["*"]
+;;
+
+let p10 = magic
+  ["x (y (x a b c))"]
+  ["*"]
+;;
+
+let p11 = magic
+  ["x x"; "x (y.y)"]
+  ["*"]
+;;
+
+let p12 = magic
+  ["x x (x x)"; "x x (x (y.y))"]
+  ["*"]
+;;
+
+let p13 = magic
+  ["x x (x x (x x x x x (x x)))"]
+  ["*"]
+;;
+
+let p14 = magic
+  ["a (a a (a (a a)) (a (a a)))"]
+  ["*"]
+;;
+
+let p15 = magic
+  ["a (a (a a)) (a a (a a) (a (a (a a))) (a (a a)) (a a (a a) (a (a (a a))) (a (a a)))) (a a (a a) (a (a (a a))) (a (a a)))"]
+  ["*"]
+;;
+
+let p16 = magic
+  ["a (a a) (a a (a (a a)) (a (a a)) (a a (a (a a)) a))"]
+  ["*"]
+;;
+
+let p17 = magic
+  ["b a"; "b (c.a)"]
+  ["*"]
+;;
+
+let p18 = magic
+  ["a (a a) (a a a (a (a (a a) a)) (a a a (a (a (a a) a))))" ; "a a" ; "a (a a)"]
+  ["*"]
+;;
+
+let p19 = magic
+  ["a (a a) (a a a (a (a (a a) a)) a)"]
+  ["*"]
+;;
+
+let p20 = magic
+  ["a (a b) (b (a b) (a (a b))) (a (a b) (a (a b)) (a (a b)) c) (a (a b) (a (a b)) (b (a b)) c (a a (a (a b) (a (a b)) b)) (a (a b) (a (a b)) (b (a b)) (a a) (a c (b (a b)))))"]["*"];;
+
+let p21 = magic
+  ["(((y z) (y z)) ((z (y z)) ((y z) (z z))))";
+   "(((z z) x) (y z))";
+   "((z (y z)) ((y z) (z z)))"
+] ["*"];;
+
+let p22 = magic
+["((z y) ((((y (z y)) x) (y (z y))) ((y (z y)) (z z))))";
+"((z y) (((((y (z y)) x) (y (z y))) ((y (z y)) (z z))) (((((y (z y)) x) (y (z y))) ((y (z y)) (z z))) ((x y) (z z)))))";
+"(y ((((y (z y)) x) (y (z y))) ((y (z y)) (z z))))"] ["*"];;
+
+(* diverging tests *)
+(* test p23 leads to test p24 *)
+let p23 = magic
+["z z z"; "z (z z) (x. x)"] ["*"];;
+
+(* because of the last term, the magic number is 1 and we diverge;
+   but setting the magic number to 0 allows to solve the problem;
+   thus our strategy is incomplete *)
+let p24 = magic
+["b b"; "b f"; "f b"; "a (x.x)"] ["*"];;
+
+(* because of the last term, the magic number is 1 and we diverge;
+   but setting the magic number to 0 allows to solve the problem;
+   thus our strategy is incomplete *)
+let p25 = magic
+["b b"; "b f"; "f b"; "f (x.x)"] ["*"];;
+
+(* BUG:
+   0 (n (d (o.n) ...)))
+   After instantiating n, the magic number (for d) should be 2, not 1! *)
+let p26 = magic
+["(((x y) (z. (y. (y. z)))) (z. y))";
+"(((x y) x) (y y))"] ["*"];;
+
+let p27 = magic
+["(((((((z y) (z (z y))) (z (z y))) ((z y) (((z y) (z (z y))) ((z y) x)))) (((((z y) (z (z y))) (z (z y))) x) y)) (((((z y) (z (z y))) (z (z y))) ((z y) (((z y) (z (z y))) ((z y) x)))) (((((z y) (z (z y))) (z (z y))) x) y))) ((((((z y) (z (z y))) (z (z y))) ((z y) (((z y) (z (z y))) ((z y) x)))) (((((z y) (z (z y))) (z (z y))) x) y)) (((((z y) (z (z y))) (z (z y))) ((z y) (((z y) (z (z y))) ((z y) x)))) (((((z y) (z (z y))) (z (z y))) x) y))))";
+"((((((z y) (z (z y))) (z (z y))) ((z y) (((z y) (z (z y))) ((z y) x)))) (((((z y) (z (z y))) (z (z y))) x) y)) (((((z y) (z (z y))) (z (z y))) ((z y) (((z y) (z (z y))) ((z y) x)))) (((((z y) (z (z y))) (z (z y))) x) y)))";
+"(((((z y) (z (z y))) (z (z y))) ((z y) (((z y) (z (z y))) ((z y) x)))) (((((z y) (z (z y))) (z (z y))) x) y))"] ["*"];;
+
+let p28 = magic
+["((((z (x. (z. (x. x)))) (z x)) x) (z (x. (z. (x. x)))))";
+ "(((z (x. (z. (x. x)))) (z x)) ((z x) (x. (z. (x. x)))))" ] ["*"];;
+
+let p29 = magic
+["((((((x x) (x x)) (z. (y x))) (z. ((x x) y))) y) ((x x) y))";
+"(((((x x) (x x)) (z. (y x))) (z. ((x x) y))) y)"] ["*"];;
+
+let p30 = magic
+["((b c) (b. (z a)))";
+"((v (a. (z v))) ((y (b c)) ((z a) (v y))))";
+"((v (v. c)) z)";
+"((v y) (v (a. (z v))))";
+"((y (b c)) ((z a) (v y)))"] ["*"];;
+
+let p31 = magic
+[" (((((((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)))";
+"((((((v (((a v) w) (((a v) w) v))) (w. c)) (b (a v))) c) (z. a)) (x. (w. (w. c))))";
+"(((((b (a v)) (a. (y c))) z) (w. w)) ((a c) c))";
+"(((((v (((a v) w) (((a v) w) v))) (w. c)) (b (a v))) c) (z. a))";
+"((((a (y c)) ((y c) ((a v) (w (z. a))))) (w. c)) (x. w))"] ["*"];;
+
+let p32 = magic
+["(((((a y) v) (z a)) (z (((z a) (z a)) (w. v)))) (y. (a y)))";
+"(((((a y) v) (z a)) (z (((z a) (z a)) (w. v)))) a)";
+"(((((z a) (z a)) b) (v. (v. (z a)))) (v. ((a y) v)))";
+"((((a y) v) (z a)) (z (((z a) (z a)) (w. v))))";
+"((((w (a. (z. ((z a) (z a))))) (v. ((a y) v))) (((z a) (z a)) b)) (w. (((z a) (z a)) (c. (c ((z a) (z a)))))))"
+] ["*"];;
+
+(* Shows an error when the strategy that minimizes special_k is NOT used *)
+let p33 = magic
+[
+"((((((v (y. v)) (w. (c. y))) ((((a (c. y)) (v w)) ((b (z (a (c. y)))) (b (z (a (c. y)))))) ((a (c. y)) b))) (((y (y (v w))) z) ((((a (c. y)) (v w)) ((b (z (a (c. y)))) (b (z (a (c. y)))))) ((a (c. y)) b)))) (b c)) (((v w) (z (a (c. y)))) ((y b) (b (z (a (c. y)))))))";
+"((((((a (c. y)) (v w)) ((b (z (a (c. y)))) (b (z (a (c. y)))))) ((a (c. y)) b)) (c. y)) (c. y))";
+"(((((a (c. y)) (v w)) ((b (z (a (c. y)))) (b (z (a (c. y)))))) ((a (c. y)) b)) (c. y))";
+"(((((a (c. y)) (v w)) ((b (z (a (c. y)))) (b (z (a (c. y)))))) (b (z (a (c. y))))) ((c b) (b. (b w))))";
+(* "(((((a (c. y)) b) v) (z (a (c. y)))) (a. (b (z (a (c. y))))))" *)
+] ["*"];;
+
+let p34 = magic [
+"b c (b c) (c (d (j. e))) (b c (b c) (j.c f)) (b f (j. k. d)) (b (j. k. l. b c (b c)) (b g)) a";
+"d (j. e) e (j. c f) (j. c j) b a";
+"d (j. e) e (j. c f) b (b c (b c) (j. c f)) a";
+"d (j. e) e (j. c f) b (b c (b c) (j. c f) (g b)) a";
+"d (j. e) e (j. c f) b (j. k. j (l. e) e (l. k f) b) a";
+] ["*"];;
+(* 0: (b c (b c) (c (d j.e)) (b c (b c) j.(c f)) (b f j.k.d) (b j.k.l.(b c (b c)) (b g)) a)
+1: (d j.e e j.(c f) j.(c j) b a)
+2: (d j.e e j.(c f) b (b c (b c) j.(c f)) a)
+3: (d j.e e j.(c f) b (b c (b c) j.(c f) (g b)) a)
+4: (d j.e e j.(c f) b j.k.(j l.e e l.(k f) b) a) *)
+
+let p35 = magic [
+"(((((((((b z) v) (a ((v (y y)) (v (y y))))) (y (v (y y)))) ((w ((a b) z)) (a ((v (y y)) (v (y y)))))) (z ((y (v (y y))) b))) (((y (v (y y))) ((y (v (y y))) x)) ((((c (a b)) (y y)) ((y (v (y y))) b)) (((c (a b)) (y y)) ((y (v (y y))) b))))) (z (z b))) ((y y) (((b z) v) (a ((v (y y)) (v (y y)))))))";
+"((((((((a b) z) w) (((b z) v) (a ((v (y y)) (v (y y)))))) ((y y) ((y (v (y y))) b))) ((((((c (a b)) (y y)) ((y (v (y y))) b)) (((c (a b)) (y y)) ((y (v (y y))) b))) (((((c (a b)) (y y)) (y (v (y y)))) (z w)) ((w (((v (y y)) (v (y y))) a)) (w (z ((y (v (y y))) b)))))) (z w))) (((((((b z) v) (a ((v (y y)) (v (y y))))) (y (v (y y)))) ((w ((a b) z)) (a ((v (y y)) (v (y y)))))) (z ((y (v (y y))) b))) (c (a b)))) (((((b z) (c b)) (c ((v (y y)) (v (y y))))) (((((c (a b)) (y y)) ((y (v (y y))) b)) (((c (a b)) (y y)) ((y (v (y y))) b))) ((c b) (z (z b))))) (((((((b z) v) (a ((v (y y)) (v (y y))))) (y (v (y y)))) (b (((v (y y)) (v (y y))) ((y y) (z (z b)))))) (((((w ((a b) z)) (a ((v (y y)) (v (y y))))) (((v (y y)) (v (y y))) a)) (((((b z) v) (a ((v (y y)) (v (y y))))) (y (v (y y)))) (b (((v (y y)) (v (y y))) ((y y) (z (z b))))))) (b z))) ((x ((c b) (c b))) (((((b z) v) (a ((v (y y)) (v (y y))))) (y (v (y y)))) ((w ((a b) z)) (a ((v (y y)) (v (y y))))))))))";
+"((((((((b z) v) (a ((v (y y)) (v (y y))))) (y (v (y y)))) ((w ((a b) z)) (a ((v (y y)) (v (y y)))))) (z ((y (v (y y))) b))) (((y (v (y y))) ((y (v (y y))) x)) ((((c (a b)) (y y)) ((y (v (y y))) b)) (((c (a b)) (y y)) ((y (v (y y))) b))))) (v (y y)))"
+] ["*"];;
+
+let p36 = magic
+[
+"(((((((y a) (((z v) (y a)) (b a))) ((b a) (b a))) (((y c) (x a)) (v (((y a) (((z v) (y a)) (b a))) z)))) ((b a) (b a))) ((a c) (b (((y a) (((z v) (y a)) (b a))) (z a))))) ((((((b (((y a) (((z v) (y a)) (b a))) z)) (c ((y (x a)) ((z v) (y a))))) (v (((y a) (((z v) (y a)) (b a))) z))) (((((y a) (((z v) (y a)) (b a))) z) (((z v) (y a)) (c y))) ((x a) (((y a) (((z v) (y a)) (b a))) z)))) ((c ((y (x a)) ((z v) (y a)))) (b (((y a) (((z v) (y a)) (b a))) z)))) ((((b (z a)) (y a)) (y c)) (a (((((y a) (((z v) (y a)) (b a))) ((b a) (b a))) (x a)) ((((y a) (((z v) (y a)) (b a))) z) (((z v) (y a)) (c y))))))))";
+"(((((((z v) (y a)) (b a)) w) b) (((b a) ((((z v) (y a)) (b a)) w)) ((((z v) (y a)) (b a)) w))) (((b a) ((((y a) (((z v) (y a)) (b a))) ((((y a) (((z v) (y a)) (b a))) ((b a) (b a))) (x a))) w)) (((c y) a) v)))";
+"(((((((z v) (y a)) (b a)) w) b) (a (((((y a) (((z v) (y a)) (b a))) ((b a) (b a))) (x a)) ((((y a) (((z v) (y a)) (b a))) z) (((z v) (y a)) (c y)))))) ((((y a) (((z v) (y a)) (b a))) ((((y a) (((z v) (y a)) (b a))) ((b a) (b a))) (x a))) x))"
+] ["*"];;
+
+(* issue with eta-equality of terms in ps *)
+let p37 = magic
+  ["x (a y) z"; "x (a z. y z) w"; "a c"]
+  ["*"];;
+
+(**********************)
+
+let q1 () = magic_conv
+ None
+ ["a d e"]
+ ["a b"; "a c"]
+ ["*"];;
+
+let q2 () = magic_conv
+ None
+ ["a d e"]
+ ["a b" ]
+ ["*"];;
+
+let q3 () = magic_conv
+ (Some "x")
+ ["a d e f"]
+ ["a b" ]
+ ["*"];;
+
+let q4 () = magic_conv
+ None
+ ["f (x.a b c d)"]
+ ["a b" ]
+ ["*"];;
+
+let q5 () = magic_conv
+ (Some"x")
+ ["(y. x)"]
+ ["x"]
+ ["*"];;
+
+let q6 () = magic_conv
+ (Some"x")
+ ["(y. x z)"]
+ ["y"]
+ ["*"];;
+
+let q7 () = magic_conv
+ (Some "(b (c d (e f f k.(g e))) f)")
+ ["(g (e f) (g e h) (f d (e f) k.e) k.(c d l.(c d)) (f d k.g (b (g (e f)) (b (g (e f)) (e f)) (g (e f) (g e h)))) k.l.(h f (b i)))";
+  "(g (e f) (g e h) (f d (e f) k.e) k.(c d l.(c d)) (b (g (e f))) k.l.(g f (k f f (k f f m.(g k)))))";
+  "(b (g (e f)) f k.e k.l.(f d (e f)) (c d (e f f k.(g e)) (g k.(e f f))) (h f (i (h k.(i b l.m.n.e)))))"]
+ ["(f d (e f) k.e k.l.(c d) (b (g e) k.h) (i b k.l.m.e b) a)";
+  "(f d (e f) k.e k.l.(c d) (b (g e) k.h) (d k.e) (f d (e f) k.e) a)";
+  "(g (e f) (g e h) (f d (e f) k.e) k.(c d l.(c d)) (g e h) (g f (e f f (e f f k.(g e))) (g (e f)) (b (c d (e f f k.(g e))) (b (g (e f)) (e f)) (b (g (e f)) k.l.e))) a)"]
+ ["*"];;
+
+(**********************)
+
+let q8 () = magic_conv
+ (Some"x a")
+ ["y (x b c)"] ["j"] ["*"]
+;;
+
+let q9 () = magic_conv
+ (Some"x a")
+ ["y x"] ["a (y a b b b)"] ["*"]
+;;
+
+let q11 () = magic_conv
+ (Some "x y")
+ ["a (x z)"] [] ["*"];;
+
+let q10 () = magic_conv
+ (Some "b (k. c) d (e (f g) (k. g)) (k. l. c) (k. l. b (m. c)) (k. l. c) (b (k. c) (k. l. b (m. c)) (k. c f)
+(k. e (f g))) (b (k. c) (k. e) f (b (k. c) (k. l. b (m. c)) (k. c f)) (b (k. c) (k. e) f (b (k. c) (k. l. b
+ (m. c)) (k. c f))) (k. b (l. c) b (l. b (m. c))) (k. b (l. c)))")
+["e (f g) (k. g) (c f) (k. e) (k. b (l. c) d (b (l. c))) (c f (k. b (l. c)) (k. l. b (m. c))) (k. l. b (m. c) d (l (f k) (m. k)) (m. n. c)) (c f (k. b (l. c)) (k. b (l. c) d) (k. c k))";
+"e (f g) (k. g) (c f) (k. i) (k. l. h) (k. l. m. n. m) (b (k. c) (k. l. b (m. c)) (k. c f)) (k. l. m. k (f g) (n. g) (c f) (n. k))";
+"b (k. c) (k. e) f (b (k. c) (k. l. b (m. c)) (k. c f)) (b (k. c) (k. e) f (b (k. c) (k. l. b (m. c)) (k. c f))) (k. b (l. c) b (l. b (m. c))) (k. b (l. c))";
+"b (k. c) d (e (f g) (k. g)) (k. l. m. n. m) (k. l. m. b (n. k) d (b (n. k))) (b (k. c) (k. e) (k. l. m. b (n. c))) (e (f g) (k. g) (c f) (k. i) (k. l. h) (k. l. m. n. m) (b (k. c) (k. l. b (m. c)) (k. c f)) (k. l. m. k (f g) (n. g) (c f) (n. k)))";
+"b (k. c) d (e (f g) (k. g)) (k. l. c) (k. l. b (m. c)) (k. l. c) (b (k. c) (k. l. b (m. c)) (k. c f) (k. e (f g)))"]
+[
+"b (k. c) (k. e) f (b (k. c) (k. l. b (m. c)) (k. c f)) (b (k. c) (k. e) f (b (k. c) (k. l. b (m. c)) (k. c f))) (k. b (l. c) b (l. b (m. c))) (e (f g) (k. g) (c f) (c f (k. b (l. c)) (k. e)))";
+"b (k. c) d (e (f g) (k. g)) (k. l. m. n. m) (k. l. m. b (n. k) d (b (n. k))) (e (f g) (k. g) (c f) (k. e) (k. b (l. c) d (b (l. c)))) (k. e (f g) (l. g) (c f) (l. k) (l. m. h))";
+"b (k. c) d (e (f g) (k. g)) (k. l. c) (k. l. b (m. c)) (k. l. m. n. o. p. o) (e (f g) (k. g) (c f) (k. i) f)";
+"b (k. c) d (e (f g) (k. g)) (k. l. c) (k. l. b (m. c)) (k. l. c) (k. b)";
+"e (f g) (k. g) (c f) (k. e) (k. b (l. c)) (c f (k. b (l. c)) (k. l. b (m. k))) (k. b (l. k)) (e (f g) (k. g) (c f) (c f (k. b (l. c)) (k. e)))";
+] ["*"];;
+
+let m1 () = magic_conv None []
+ ["y z"; "x z"; "x (a k) u"; "x (a r)"; "x (a k) v"]
+ ["*"]
+;;
+
+let m2 () = magic_conv None []
+ ["y z"; "x z"; "x (a k) u"; "x (a r)"; "x (a k) v"]
+ ["*"]
+;;
+
+main ([
+ (* p2 ; p4 ; p5 ; p6 ; p7 ; p8 ; p9 ; p10 ; p11 ; p12 ; p13 ; p14 ; p15 ; p16 ; p17 ; p18 ; p19 ; p20 ; p21 ; p22 ; p23 ; p24 ; p25 ; p26 ; p27 ; p28 ; p29 ; p30 ; p31 ; p32 ; p33 ; p34 ; p35 ; p36 ; p37 ; *)
+ p24 ; p25 ;
+] @ if use_lambda3 then [] else List.map ((|>) ()) [
+ q1 ; q2; q3; q4 ; q5 ; q6 ;
+ (* q7 ; *)
+ q8 ;
+ q9 ;
+ q10 ;
+ q11 ;
+ m1 ;
+]);;
diff --git a/ocaml/problems.mli b/ocaml/problems.mli
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/ocaml/pure.ml b/ocaml/pure.ml
new file mode 100644 (file)
index 0000000..78c6c4c
--- /dev/null
@@ -0,0 +1,122 @@
+open Util.Vars
+
+module Pure =
+struct
+
+type t =
+  | V of int
+  | A of t * t
+  | L of t
+
+let rec print ?(l=[]) =
+ function
+    V n -> print_name l n
+  | A(t1,t2) -> "(" ^ print ~l t1 ^ " " ^ print ~l t2 ^ ")"
+  | L t ->
+     let name = string_of_var (List.length l) in
+     "λ" ^ name ^ "." ^ print ~l:(name::l) t
+
+let lift m =
+ let rec aux l =
+  function
+   | V n -> V (if n < l then n else n+m)
+   | A (t1,t2) -> A (aux l t1, aux l t2)
+   | L t -> L (aux (l+1) t)
+ in
+  aux 0
+
+(* Reference implementation.
+   Reduction machine used below
+let subst delift_by_one what with_what =
+ let rec aux l =
+  function
+   | A(t1,t2) -> A(aux l t1, aux l t2)
+   | V n ->
+       if n = what + l then
+        lift l with_what
+       else
+        V (if delift_by_one && n >= l then n-1 else n)
+   | L t -> L (aux (l+1) t)
+ in
+  aux 0
+
+let rec whd =
+ function
+  | A(t1, t2) ->
+     let t2 = whd t2 in
+     let t1 = whd t1 in
+      (match t1 with
+        | L f -> whd (subst true 0 t2 f)
+        | V _
+        | A _ -> A(t1,t2))
+  | V _
+  | L _ as t -> t
+*)
+
+let unwind ?(tbl = Hashtbl.create 317) m =
+ let rec unwind (e,t,s) =
+  let cache_unwind m =
+   try
+    Hashtbl.find tbl m
+   with
+    Not_found ->
+     let t = unwind m in
+      Hashtbl.add tbl m t ;
+      t in
+  let s = List.map cache_unwind s in
+  let rec aux l =
+   function
+    | A(t1,t2) -> A(aux l t1, aux l t2)
+    | V n as x when n < l -> x
+    | V n ->
+       (try
+         lift l (cache_unwind (List.nth e (n - l)))
+        with Failure _ -> V (n - l))
+    | L t -> L (aux (l+1) t) in
+  let t = aux 0 t in
+  List.fold_left (fun f a -> A(f,a)) t s
+in
+ unwind m
+
+let mwhd m =
+ let rec aux =
+  function
+     (e,A(t1,t2),s) ->
+       let t2' = aux (e,t2,[]) in
+       aux (e,t1,t2'::s)
+   | (e,L t,x::s) -> aux (x::e,t,s)
+   | (e,V n,s) as m ->
+      (try
+        let e,t,s' = List.nth e n in
+        aux (e,t,s'@s)
+       with Failure _ -> m)
+   | (_,L _,[]) as m -> m
+ in
+  unwind (aux m)
+
+end
+
+module Scott =
+struct
+
+open Pure
+
+let rec mk_n n =
+ if n = 0 then L (L (A (V 1, L (V 0)))) else L (L (A (V 0, mk_n (n-1))))
+
+let dummy = V (max_int / 2)
+
+let mk_match t bs =
+ let bs = List.sort (fun (n1,_) (n2,_) -> compare n1 n2) bs in
+ let rec aux m t =
+  function
+     [] -> dummy
+   | (n,p)::tl as l ->
+      if n = m then
+       A (A (t, L (lift (m+1) p)), L (aux (m+1) (V 0) tl))
+      else
+       A (A (t, dummy), L (aux (m+1) (V 0) l))
+ in
+  aux 0 t bs
+
+end
diff --git a/ocaml/pure.mli b/ocaml/pure.mli
new file mode 100644 (file)
index 0000000..f360074
--- /dev/null
@@ -0,0 +1,15 @@
+module Pure :
+  sig
+    type t = V of int | A of t * t | L of t
+    val print : ?l:string list -> t -> string
+    val lift : int -> t -> t
+    val unwind : ?tbl:('a list * t * 'a list as 'a, t) Hashtbl.t -> 'a -> t
+    val mwhd : (('a * t * ('b list as 'c) as 'b) list as 'a) * t * 'c -> t
+  end
+
+module Scott :
+  sig
+    val mk_n : int -> Pure.t
+    val dummy : Pure.t
+    val mk_match : Pure.t -> (int * Pure.t) list -> Pure.t
+  end
diff --git a/ocaml/test.ml b/ocaml/test.ml
new file mode 100644 (file)
index 0000000..2f6017a
--- /dev/null
@@ -0,0 +1,95 @@
+let three = Array.length Sys.argv = 1;;
+
+let discriminator =
+ if three
+ then (module Lambda3 : Discriminator.Discriminator)
+ else (module Lambda4);;
+
+module Pippo = (val discriminator);;
+open Pippo;;
+
+let acaso l =
+    let n = Random.int (List.length l) in
+    List.nth l n
+;;
+
+let acaso2 l1 l2 =
+  let n1 = List.length l1 in
+  let n = Random.int (n1 + List.length l2) in
+  if n >= n1 then List.nth l2 (n - n1) else List.nth l1 n
+;;
+
+let rec take l n =
+  if n = 0 then []
+  else match l with
+  | [] -> []
+  | x::xs -> x :: (take xs (n-1))
+;;
+
+let test3 n vars =
+  let rec aux n inerts lams =
+    if n = 0 then take (Util.sort_uniq inerts) 5
+    else let inerts, lams = if Random.int 2 = 0
+      then inerts, ("(" ^ acaso vars ^ ". " ^ acaso2 inerts lams ^ ")") :: lams
+      else ("(" ^ acaso inerts ^ " " ^ acaso2 inerts lams^ ")") :: inerts, lams
+    in aux (n-1) inerts lams
+  in aux (2*n) vars []
+;;
+
+let test4 n vars =
+  let rec take' l n =
+    if n = 0 then [], []
+    else match l with
+    | [] -> [], []
+    | [_] -> assert false
+    | x1::x2::xs -> let a, b = take' xs (n-1) in x1::a,x2::b in
+  let rec aux n inerts lams =
+    if n = 0 then List.hd inerts, take' (Util.sort_uniq (List.tl inerts)) 5
+    else let inerts, lams = if Random.int 2 = 0
+      then inerts, ("(" ^ acaso vars ^ ". " ^ acaso2 inerts lams ^ ")") :: lams
+      else ("(" ^ acaso inerts ^ " " ^ acaso2 inerts lams^ ")") :: inerts, lams
+    in aux (n-1) inerts lams
+  in aux (2*n) vars []
+;;
+
+
+let rec repeat f n =
+  prerr_endline "\n*************************** NEW TEST ***************************";
+  f () ;
+  if n > 0 then repeat f (n-1)
+;;
+
+let call_main3 tms =
+  let _ = (
+  List.iter prerr_endline tms; prerr_newline ();
+  ) in Lambda3.main [Lambda3.magic tms ["*"]]
+;;
+let call_main4 div convs nums =
+  let _ = (
+  (match div with Some div -> prerr_endline ("DIV: " ^ div) | None -> ());
+  print_endline "CONV:"; List.iter prerr_endline convs;
+  print_endline "NUMS:"; List.iter prerr_endline nums;
+  prerr_newline ();
+  ) in Lambda4.main [Lambda4.magic_conv div convs nums ["*"]]
+;;
+
+let main =
+  Random.self_init ();
+  let num = 100 in
+  let complex = 200 in
+  let vars = ["x"; "y"; "z"; "v" ; "w"; "a"; "b"; "c"] in
+
+  (* let open Parser in *)
+
+  if three then repeat (fun _ ->
+    let tms = test3 complex vars in
+    call_main3 tms
+  ) num
+  else repeat (fun _ ->
+    let div, (conv, nums) = test4 complex vars in
+    call_main4 (Some div) conv nums
+  ) num
+  ;
+
+  prerr_endline "\n---- ALL TESTS COMPLETED ----"
+;;
diff --git a/ocaml/test1.ml b/ocaml/test1.ml
new file mode 100644 (file)
index 0000000..424ec72
--- /dev/null
@@ -0,0 +1,73 @@
+
+
+let acaso l =
+    let n = Random.int (List.length l) in
+    List.nth l n
+;;
+
+let acaso2 l1 l2 =
+  let n1 = List.length l1 in
+  let n = Random.int (n1 + List.length l2) in
+  if n >= n1 then List.nth l2 (n - n1) else List.nth l1 n
+;;
+
+let rec take l n =
+  if n = 0 then []
+  else match l with
+  | [] -> []
+  | x::xs -> x :: (take xs (n-1))
+;;
+
+let test1 n vars =
+  let rec aux n l =
+    if n = 0
+      then take (Util.sort_uniq l) 3
+      else aux (n-1) (("(" ^ (acaso l) ^ " " ^ (acaso l) ^ ")") :: l)
+  in aux n vars
+;;
+
+let test2 n vars =
+  let rec aux n ins lams =
+    if n = 0 then take (Util.sort_uniq ins) 5
+    else let ins, lams = if Random.int 2 = 0
+      then ins, ("(" ^ acaso vars ^ ". " ^ acaso2 ins lams ^ ")") :: lams
+      else ("(" ^ acaso ins ^ " " ^ acaso2 ins lams^ ")") :: ins, lams
+    in aux (n-1) ins lams
+  in aux (2*n) vars []
+;;
+
+
+let rec repeat f n = f () ; if n > 0 then repeat f (n-1);;
+
+let call_main tms =
+  let _ = (
+  prerr_endline "\n*************************** NEW TEST ***************************";
+  List.iter prerr_endline tms; prerr_endline "";
+  ) in Lambda3.main [Lambda3.magic tms ["*"]]
+;;
+
+let main =
+  Random.self_init ();
+  (*Random.init 1000;*)
+  let num = 100 in
+  let complex = 200 in
+  let vars = ["x"; "y"; "z"; "v" ; "w"; "a"; "b"; "c"] in
+
+  let open Parser in
+  let open Lambda3 in
+
+  (* test1 *)
+  repeat (fun _ ->
+    let tms = test1 complex vars in
+    call_main tms
+  ) num
+  ;
+
+  (* test2 *)
+  repeat (fun _ ->
+    call_main (test2 complex vars)
+  ) num
+  ;
+
+  prerr_endline "\n---- ALL TESTS COMPLETED ----"
+;;
diff --git a/ocaml/util.ml b/ocaml/util.ml
new file mode 100644 (file)
index 0000000..a4af2dd
--- /dev/null
@@ -0,0 +1,113 @@
+(* Function composition *)
+let (++) f g x = f (g x);;
+
+let findi p =
+ let rec aux n = function
+ | [] -> raise Not_found
+ | x::_ when p x -> n, x
+ | _::xs -> aux (n+1) xs
+ in aux 0
+;;
+
+let option_map f = function
+ | None -> None
+ | Some x -> Some (f x)
+;;
+
+let rec find_opt f =
+ function
+    [] -> None
+  | x::xs ->
+     match f x with
+        None -> find_opt f xs
+      | Some _ as res -> res
+
+let rec index_of ?(eq=(=)) x =
+ function
+    [] -> raise Not_found
+  | y::_ when eq x y -> 0
+  | _::l -> 1 + index_of ~eq x l
+
+let index_of_opt ?eq l t =
+ try
+  Some (index_of ?eq t l)
+ with
+  Not_found -> None
+;;
+
+let rec filter_map f =
+ function
+    [] -> []
+  | hd::tl ->
+     match f hd with
+        None -> filter_map f tl
+      | Some x -> x::filter_map f tl
+;;
+
+(* the input must be sorted *)
+let rec first_duplicate =
+ function
+    []
+  | [_] -> None
+  | x::y::_ when x=y -> Some x
+  | _::tl -> first_duplicate tl
+
+(* the input must be sorted
+   output: list of non duplicates; list of duplicates *)
+let rec split_duplicates =
+ function
+    [] -> [],[]
+  | [x] -> [x],[]
+  | x::(y::_ as tl) ->
+     let nondup,dup = split_duplicates tl in
+     if x = y then
+      List.filter ((<>) x) nondup, x::dup
+     else
+      x::nondup,dup
+
+(* Non c'e' nella vecchia versione di OCaml :( *)
+let uniq ?(compare=compare) =
+  let rec aux = function
+  | [] -> []
+  | [_] as ts -> ts
+  | t1 :: (t2 :: _ as ts) ->
+    if compare t1 t2 = 0 then aux ts else t1 :: (aux ts)
+  in aux
+
+let sort_uniq ?(compare=compare) l = uniq ~compare (List.sort compare l)
+
+let rec list_cut = function
+  | 0, lst -> [], lst
+  | n, x::xs -> let a, b = list_cut (n-1,xs) in x::a, b
+  | _ -> assert false
+;;
+
+let concat_map f l = List.concat (List.map f l);;
+
+let rec take n =
+ function
+ | [] -> assert (n = 0); []
+ | _ when n = 0 -> []
+ | x::xs -> x::(take (n-1) xs)
+;;
+
+module Vars =
+struct
+
+let string_of_var v =
+  if v > 25
+     then "`" ^ string_of_int v
+     else String.make 1 (char_of_int (v + int_of_char 'a'))
+;;
+
+let var_of_string s =
+ if String.length s <> 1 then (
+   if s.[0] = '`' then int_of_string (String.sub s 1 (-1 + String.length s)) else assert false
+ ) else int_of_char s.[0] - int_of_char 'a'
+
+let print_name l n =
+ if n = -1
+  then "*"
+  else if n >= List.length l then "x" ^ string_of_int (List.length l - n - 1) else List.nth l n
+
+end
diff --git a/ocaml/util.mli b/ocaml/util.mli
new file mode 100644 (file)
index 0000000..751225a
--- /dev/null
@@ -0,0 +1,20 @@
+val ( ++ ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
+val findi : ('a -> bool) -> 'a list -> (int * 'a)
+val option_map : ('a -> 'b) -> 'a option -> 'b option
+val find_opt : ('a -> 'b option) -> 'a list -> 'b option
+val index_of : ?eq:('a -> 'a -> bool) -> 'a -> 'a list -> int
+val index_of_opt : ?eq:('a -> 'a -> bool) -> 'a list -> 'a -> int option
+val filter_map : ('a -> 'b option) -> 'a list -> 'b list
+val first_duplicate : 'a list -> 'a option
+val split_duplicates : 'a list -> 'a list * 'a list
+val uniq : ?compare:('a -> 'a -> int) -> 'a list -> 'a list
+val sort_uniq : ?compare:('a -> 'a -> int) -> 'a list -> 'a list
+val list_cut : (int * 'a list) -> ('a list * 'a list)
+val concat_map : ('a -> 'b list) -> 'a list -> 'b list
+val take : int -> 'a list -> 'a list
+module Vars :
+  sig
+    val string_of_var : int -> string
+    val var_of_string : string -> int
+    val print_name : string list -> int -> string
+  end