From e4aa4a66dd0a4946607245a0f43eab803f2770c4 Mon Sep 17 00:00:00 2001 From: Date: Mon, 12 Jun 2017 22:28:38 +0200 Subject: [PATCH] Copy ocaml folder from sacerdot's svn repository, rev 4907 --- ocaml/Makefile | 36 ++ ocaml/andrea3.ml | 364 ++++++++++++++++++ ocaml/andrea5.ml | 27 ++ ocaml/andrea6.ml | 474 +++++++++++++++++++++++ ocaml/console.ml | 141 +++++++ ocaml/console.mli | 24 ++ ocaml/discriminator.mli | 6 + ocaml/lambda3.ml | 550 +++++++++++++++++++++++++++ ocaml/lambda3.ml.ar | 550 +++++++++++++++++++++++++++ ocaml/lambda3.mli | 1 + ocaml/lambda4.ml | 821 ++++++++++++++++++++++++++++++++++++++++ ocaml/lambda4.mli | 1 + ocaml/listx.ml | 68 ++++ ocaml/listx.mli | 11 + ocaml/mk_andrea | 3 + ocaml/num.ml | 294 ++++++++++++++ ocaml/num.ml.ar | 294 ++++++++++++++ ocaml/num.mli | 43 +++ ocaml/num.mli.ar | 43 +++ ocaml/numx.ml | 294 ++++++++++++++ ocaml/numx.mli | 44 +++ ocaml/parser.ml | 153 ++++++++ ocaml/parser.mli | 9 + ocaml/problems.ml | 304 +++++++++++++++ ocaml/problems.mli | 0 ocaml/pure.ml | 122 ++++++ ocaml/pure.mli | 15 + ocaml/test.ml | 95 +++++ ocaml/test1.ml | 73 ++++ ocaml/util.ml | 113 ++++++ ocaml/util.mli | 20 + 31 files changed, 4993 insertions(+) create mode 100644 ocaml/Makefile create mode 100644 ocaml/andrea3.ml create mode 100644 ocaml/andrea5.ml create mode 100644 ocaml/andrea6.ml create mode 100644 ocaml/console.ml create mode 100644 ocaml/console.mli create mode 100644 ocaml/discriminator.mli create mode 100644 ocaml/lambda3.ml create mode 100644 ocaml/lambda3.ml.ar create mode 100644 ocaml/lambda3.mli create mode 100644 ocaml/lambda4.ml create mode 100644 ocaml/lambda4.mli create mode 100644 ocaml/listx.ml create mode 100644 ocaml/listx.mli create mode 100644 ocaml/mk_andrea create mode 100644 ocaml/num.ml create mode 100644 ocaml/num.ml.ar create mode 100644 ocaml/num.mli create mode 100644 ocaml/num.mli.ar create mode 100644 ocaml/numx.ml create mode 100644 ocaml/numx.mli create mode 100644 ocaml/parser.ml create mode 100644 ocaml/parser.mli create mode 100644 ocaml/problems.ml create mode 100644 ocaml/problems.mli create mode 100644 ocaml/pure.ml create mode 100644 ocaml/pure.mli create mode 100644 ocaml/test.ml create mode 100644 ocaml/test1.ml create mode 100644 ocaml/util.ml create mode 100644 ocaml/util.mli diff --git a/ocaml/Makefile b/ocaml/Makefile new file mode 100644 index 0000000..3310c6e --- /dev/null +++ b/ocaml/Makefile @@ -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 index 0000000..2796107 --- /dev/null +++ b/ocaml/andrea3.ml @@ -0,0 +1,364 @@ +type var = (* unique name *) int * (int * term) option * (*level*) int +and term = + | Tvar of var + | Tapp of term * term + | Tlam of int * term +;; + +let zero = Tvar(1010, None, 0);; +let dummy = Tvar(333, None, 0);; + +(* mk_app & subst implementano la beta *) +let rec mk_app t1 t2 = match t1 with + | Tlam(v, t1') -> subst v t2 t1' + | _ -> Tapp(t1, t2) +and subst v tv = + let rec aux = function + | Tapp(t1, t2) -> mk_app (aux t1) (aux t2) + | Tvar(v', _, _) as t -> if v = v' then tv else t + | Tlam(v', t') as t -> if v = v' then t else Tlam(v', aux t') + in aux +;; + +(* PARSING AND PRINTING *) + +let parse = + let rec minus1 = function + | Tvar(n, None, x) -> Tvar(n-1, None, x) + | Tvar _ -> assert false + | Tapp(t1, t2) -> Tapp(minus1 t1, minus1 t2) + | Tlam(n, t) -> Tlam(n-1, minus1 t) + (* in let open Parser *) + in let rec myterm_of_term = function + | Parser.Var n -> Tvar(n, None, 0) + | Parser.App(t1, t2) -> (*Tapp(myterm_of_term t1, myterm_of_term t2) WARNING! BETA DOWN HERE! *) + mk_app (myterm_of_term t1) (myterm_of_term t2) + | Parser.Lam(t) -> minus1 (Tlam(0, myterm_of_term t)) + in fun strs -> ( + let (tms, free) = Parser.parse_many strs + in List.map myterm_of_term tms + ) +;; + +(* PRETTY PRINTING *) +open Console;; + +let fancy_of_term t = +let rec string_of_term = + let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"] in + let bound = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"] in + let string_of_int' n = if n >= 0 then List.nth free (n) else List.nth bound (-n-1) in + let rec string_of_var t = + if Tvar t = dummy then "_" else if Tvar t = zero then "ZZ" else match t with + | (n, None, _) -> (string_of_int' n) + (* | (_, Some(n,t), _) -> "?" ^ string_of_int n *) + | (_, Some(n,t), _) -> "{" ^ (string_of_term_no_pars t) ^ "|" ^ (string_of_int n) ^ "}" + and string_of_term_w_pars = function + | Tvar v -> string_of_var v + | Tapp(t1, t2) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")" + | Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")" + and string_of_term_no_pars_app = function + | Tapp(t1, t2) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) + | _ as t -> string_of_term_w_pars t + and string_of_term_no_pars_lam = function + | Tlam(v, t) -> "λ" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t) + | _ as t -> string_of_term_no_pars t + and string_of_term_no_pars = function + | Tlam(_, _) as t -> string_of_term_no_pars_lam t + | _ as t -> string_of_term_no_pars_app t + in string_of_term_no_pars +in let rec html_of_term = + let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"; "h"; "i"; "j"] in + let bound = ["x"; "y"; "z"; "w"; "q"] in + let string_of_int' n = if n >= 0 then List.nth free (n) else List.nth bound (-n-1) in + let rec string_of_var t = + if Tvar t = dummy then "#" else if Tvar t = zero then "Z" else match t with + | (n, None, _) -> (string_of_int' n) + | (_, Some(n,t), _) -> "α" ^ (string_of_term_no_pars t) ^ "" ^ (string_of_int n) ^ "" + and string_of_term_w_pars = function + | Tvar v -> string_of_var v + | Tapp(t1, t2) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")" + | Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")" + and string_of_term_no_pars_app = function + | Tapp(t1, t2) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) + | _ as t -> string_of_term_w_pars t + and string_of_term_no_pars_lam = function + | Tlam(v, t) -> "λ" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t) + | _ as t -> string_of_term_no_pars t + and string_of_term_no_pars = function + | Tlam(_, _) as t -> string_of_term_no_pars_lam t + | _ as t -> string_of_term_no_pars_app t + in string_of_term_no_pars +in + string_of_term t / html_of_term t +;; + +let fancy_of_nf t: Console.fancyobj = +let rec print ?(l=[]) = + function + `Var n -> Lambda3.print_name l n + | `N n -> string_of_int n + | `Match(t,bs_lift,bs,args) -> + "([" ^ print ~l (t :> Lambda3.nf) ^ + " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Lambda3.lift bs_lift t)) !bs) ^ "] " ^ + String.concat " " (List.map (print ~l) args) ^ ")" + | `I(n,args) -> "(" ^ Lambda3.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")" + | `Lam nf -> + let name = Lambda3.string_of_var (List.length l) in + "" ^ name ^ "." ^ print ~l:(name::l) (nf : Lambda3.nf) + +in let rec print_html ?(l=[]) = + function + `Var n -> Lambda3.print_name l n + | `N n -> string_of_int n + | `Match(t,bs_lift,bs,args) -> + "(match " ^ print_html ~l (t :> Lambda3.nf) ^ + " with " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " " ^ print_html ~l (Lambda3.lift bs_lift t)) !bs) ^ "..." (* Attenzion non sto stampando gli argomenti applicati! Perche' non ce ne sono mai *) + | `I(n,args) -> "(" ^ Lambda3.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print_html ~l) args)) ^ ")" + | `Lam nf -> + let name = Lambda3.string_of_var (List.length l) in + "λ" ^ name ^ ". " ^ print_html ~l:(name::l) (nf : Lambda3.nf) +in + print t / print_html t +;; + +let print_term t = print_endline (fancy_of_term t :> Console.fancyobj);; +(* *) + + +let varcount = ref 0;; + +let freshvar () = ( + varcount := (!varcount + 1); + !varcount +);; + +let rec hd = + function + | Tvar x -> x + | Tapp(t1,t2) -> hd t1 + | Tlam _ -> assert false +;; + +let alive (_, _, n) = n;; +let rec setalive c = function + | Tvar(a,b,_) as v -> if v <> zero && v <> dummy then Tvar(a,b,c) else v + | Tapp(a,b) -> Tapp(setalive c a, setalive c b) + | Tlam(n, t) -> Tlam(n, setalive c t) +;; + +let mk_vars t lev = + let rec aux n = + if n = 0 + then [] + else Tvar(0, Some(n, t), lev) :: (aux (n-1)) + in aux +;; + +let mk_apps t ts = List.fold_right (fun x y -> mk_app y x) (List.rev ts) t;; (* which FOLD? FIXME *) + + +let compute_special_k tms = + let rec aux k t = match t with + | Tvar _ -> 0 + | Tapp(t1,t2) -> Pervasives.max (aux 0 t1) (aux 0 t2) + | Tlam(v,t) -> Pervasives.max (k+1) (aux (k + 1) t) + in List.fold_left (fun b a -> Pervasives.max (aux 0 a) b) 0 tms +;; + +let compute_special_h tms = + let rec eat_lam = function + | Tlam(_,t) -> eat_lam t + | _ as t -> t + in + let rec aux t = match t with + | Tvar _ -> 0 + | Tapp(t1,t2) -> Pervasives.max (aux t1) (aux t2) + | Tlam(v,t) -> 1 + (aux (eat_lam t)) + in 1 + List.fold_left (fun b a -> Pervasives.max (aux a) b) 0 tms +;; + +(* funzione di traduzione brutta & cattiva *) +let translate k = + let rec aux = function + | Tlam _ -> assert false + | Tvar _ as v -> v + | Tapp(t1, t2) -> + let v = hd t1 in + let a = alive v in + let t1' = aux t1 in + let t2' = if a = 0 + then t2 + else mk_apps t2 ((List.rev (mk_vars t1' (a-1) k)) @ [zero]) + in Tapp(t1', aux t2') + in aux +;; + +(* sostituisce gli argomenti dummy (delle variabili morte) con 'dummy' *) +let rec dummize = function + | Tlam _ -> assert false + | Tvar (a,Some(b,t), c) -> Tvar(a, Some (b, dummize t), c) + | Tvar _ as v -> v + | Tapp(t1, t2) -> + if alive (hd t1) = 0 + then Tapp(dummize t1, dummy) + else Tapp(dummize t1, dummize t2) +;; + +(* lista di sottotermini applicativi *) +let rec subterms = function + | Tlam _ -> assert false + | Tvar _ as v -> [v] + | Tapp(t1, t2) -> Tapp(t1, t2) :: ((subterms t1) @ (subterms t2)) +;; + +(* filtra dai sottotermini le variabili *) +let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;; + + +let rec stupid_uniq = function + | [] -> [] + | x::xs -> if List.mem x xs then (stupid_uniq xs) else x::(stupid_uniq xs) +;; +let stupid_compare a b = + let rec size = function + | Tvar(_,None,_) -> 0 + | Tvar(_,Some(_,t),_) -> 1 + size t + | Tapp(t1,t2) -> 1 + size t1 + size t2 + | Tlam _ -> assert false + in compare (size a) (size b) +;; +let stupid_sort_uniq l = stupid_uniq (List.sort stupid_compare l);; + +(* crea i match ricorsivamente. + - k e' lo special-K + - subs e' l'insieme dei sottotermini + TODO: riscrivere la funzione per evitare/ottimizzare la ricorsione + *) +let crea_match k subs (acc : (term * Lambda3.nf) list) : term -> Lambda3.nf = + let req t = try List.assoc t acc with Not_found -> `Var 9999 in + let aux t1 = ( + if t1 = dummy then `Var 99999 else + (* let _ = print_term t1 in *) + let cont = List.filter (fun t2 -> List.mem (Tapp(t1,t2)) subs) subs + in if cont = [] then + try `N (Lambda3.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else + let a = alive (hd t1) in + if a = 0 then `Lam (req (Tapp(t1, dummy))) + else ( + let vars = (List.rev (mk_vars t1 (a-1) k)) @ [zero] + (* in let _ = print_endline (String.concat " " (List.map string_of_term vars)) + in let _ = print_term (mk_apps dummy vars) *) + in let vars = List.map req vars + in let vars = List.map (Lambda3.lift 1) vars (* forse lift non necessario *) + in let vars = Listx.from_list vars + in let body = `I(0, vars) + in let branches = List.map (fun t2 -> (Lambda3.index_of t2 subs, req (Tapp(t1, t2)))) cont + in let bs = ref(branches) + in let lift = 1 + in let args = [] + in `Lam (`Match(body, lift, bs, args)) + ) + ) in aux +;; + +let mk_zeros k = + let rec aux n prev = + if n = 0 then [zero] + else let prev = aux (n-1) prev in let x = mk_app (List.hd prev) dummy in x :: prev + in aux (k+1) [] +;; + +let is_scott_n t n = + let open Lambda3 in let open Pure in + let rec aux n = function + | L (L (A (V 1, L (V 0)))) -> n = 0 + | L (L (A (V 0, t))) -> aux (n-1) t + | _ -> assert false + in aux n t +;; + +(* do the magic *) +let magic strings k h = ( + let tms = parse strings + in let tms = List.map (fun x -> Tapp(x, zero)) tms + in let tms' = List.map (setalive h) tms + in let tms' = List.map (translate k) tms' + in let tms' = List.map dummize tms' + in let progress s = print_bullet (fancy_of_string s) + in let _ = progress "traduzione completata" + (* in let _ = List.map print_term tms' *) + in let _ = progress "ordino i sottotermini" + in let subs = List.concat (List.map subterms tms') + in let subs = stupid_sort_uniq subs + (* metti gli zeri in testa, perche' vanno calcolati per primi *) + in let zeros = mk_zeros k + in let subs = (List.filter (fun t -> not (List.mem t zeros)) subs) @ (List.rev zeros) + in let _ = progress ("sottotermini generati: " ^ string_of_int (List.length subs)) + in let vars = vars subs + (* in let _ = List.iter print_term subs *) + (* in let _ = 0/0 *) + in let fv = List.filter (function Tvar(_, None, _) as v -> v <> dummy | _ -> false) vars + (* in let _ = print_string ("> free vars: " ^ String.concat ", " (List.map (string_of_term) fv)) *) + in let _ = progress "sto creando i match" + (* in let sigma = List.map (fun x -> x, crea_match k subs x) fv *) + in let f t acc = let res = crea_match k subs acc t in (t,res)::acc + in let acc = List.fold_right f subs [] + in let sigma = List.filter (fun (t,res) -> List.mem t fv) acc + in let _ = progress "match creati" + in let _ = List.iter (fun (x,y) -> print_endline (fancy_of_term x ^^ (" : " / " ↦ ") ^^ fancy_of_nf y)) sigma + + in let _ = progress "controllo di purezza"; + in let open Lambda3 + in let ps, _ = Lambda3.parse' strings + in let ps = List.map (fun x -> Lambda3.mk_app x (`Var 1010)) ps + in let ps = List.map (fun t -> ToScott.t_of_nf (t :> nf)) ps + in let sigma = List.map ( + function (Tvar(n,_,_), inst) -> n, ToScott.t_of_nf inst | _ -> assert false + ) sigma + in let ps = + List.fold_left (fun ps (x,inst) -> List.map (Pure.subst false x inst) ps) ps sigma + in let _ = List.iteri (fun i n -> + (* print_string_endline ((string_of_int i) ^ ":: " ^ (Pure.print (Pure.whd n))); *) + (* assert (Pure.whd n = Scott.mk_n (Lambda3.index_of (List.nth tms' i) subs))) ps *) + assert (is_scott_n (Pure.whd n) (Lambda3.index_of (List.nth tms' i) subs))) ps + in let _ = progress "fatto." in () +);; + +let do_everything tms = +let tms' = parse tms in +let _ = List.iter print_term tms' in +let k = compute_special_k tms' in +let h = compute_special_h tms' in +(* let _ = print_string_endline (string_of_int h) in *) +magic tms k h +;; + +let _ = + let tms = ["a a"; "a b"; "b a"; "b (x. y.x y a)"] in + (* 1 2 *) + (* let tms = ["x c" ; "b (x c d e)"; "b"] in *) + (* 0 1 *) + (* let tms = ["x x x"] in *) + let tms' = parse tms in + let _ = List.iter print_term tms' in + let k = compute_special_k tms' in + let h = compute_special_h tms' in + (* let _ = print_string_endline (string_of_int h) in *) + magic tms k h +;; + +(* type var' = (* unique name *) int * (int * term') option * (*dead*) bool option +and term' = + | Tvar' of var' + | Tapp' of term' * term' * (* active *) bool + | Tlam' of int * term' +;; + +let rec iter mustapply = + let aux = function + | Tvar'(n, Some(m,t), b) -> Tvar(n, Some(m, aux t), b) + | Tvar' _ as v -> v + | Tapp'(t1, t2, b) -> if b && + in aux +;; *) diff --git a/ocaml/andrea5.ml b/ocaml/andrea5.ml new file mode 100644 index 0000000..eadb645 --- /dev/null +++ b/ocaml/andrea5.ml @@ -0,0 +1,27 @@ +(* percorsi di differenza etc. *) + +open Lambda3;; + +type formula = + | Var of int + | And of formula * formula + | Or of formula * formula +;; + +let rec mk_k_vars k = + if k = 0 then [] + else `Var (k-1) :: (mk_k_vars (k-1)) +;; + +let is_lambda = function + | `Lam _ -> true + | _ -> false +;; + +let rec diff k level t1 t2 = + if is_lambda t1 || is_lambda t2 + then let vars = mk_k_vars k in + let level = level + k in + diff k level (mk_appl (lift k t1) vars) (mk_appl (lift k t2) vars) + else assert false +;; diff --git a/ocaml/andrea6.ml b/ocaml/andrea6.ml new file mode 100644 index 0000000..34c0788 --- /dev/null +++ b/ocaml/andrea6.ml @@ -0,0 +1,474 @@ +let print_hline = Console.print_hline;; + +type var = int;; + +type t = + | V of var + | A of t * t + | L of t + | LM of + t list (* body of the match *) + * int (* explicit liftno *) + * int (* variable which originated this match (id) *) + | B (* bottom *) + | P (* pacman *) +;; + + +type problem = { + freshno : int + ; div : t + ; conv : t list + ; matches : (var (* variable originating this match *) * (t (* term to discriminate *) * t (* continuation *)) list) list + ; sigma : (var * t) list (* substitutions *) +} + +let string_of_t p = + let bound_vars = ["x"; "y"; "z"; "z1"; "z2"] in + let rec aux level = function + | V v -> if v >= level then "`" ^ string_of_int (v-level) else List.nth bound_vars (level - v-1) + | A (t1,t2) -> "("^aux level t1^" "^aux level t2^")" + | L t -> "(\\" ^ aux (level+1) (V 0) ^ ". " ^ aux (level+1) t ^ ")" + | LM (ts,liftno,id) -> "[match orig="^aux 0 (V id)^"]" + | B -> "BOT" + | P -> "PAC" + in aux 0 +;; + +let string_of_problem p = + let lines = [ + "[DV] " ^ string_of_t p p.div; + "[CV] " ^ String.concat "\n " (List.map (string_of_t p) p.conv); + "" ; + ] @ Util.concat_map (fun (_, lst) -> "[<>]" :: List.map (fun (t,c) -> " " ^ string_of_t p t + (* ^" -> " ^ string_of_t p c *) + ) lst) p.matches @ [""] in + String.concat "\n" lines +;; + +let problem_fail p reason = + print_endline " FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL"; + print_endline (string_of_problem p); + failwith reason +;; + +let freshvar ({freshno} as p) = + {p with freshno=freshno+1}, freshno+1 +;; + +let add_to_match p id entry = + let matches = try + let _ = List.assoc id p.matches in + List.map (fun (id',lst as x) -> if id <> id' then x else (id, entry::lst) ) p.matches + with + | Not_found -> (id,[entry]) :: p.matches in + {p with matches=matches} +;; + +let free_in v = + let rec aux level = function + | V v' -> v + level = v' + | A(t1,t2) -> (aux level t1) || (aux level t2) + | L t -> aux (level+1) t + | LM(ts,_,_) -> List.fold_left (fun a b -> a || aux (level+1) b) false ts + | B -> false + | P -> false + in aux 0 +;; + +let rec is_inert = + function + | A(t,_) -> is_inert t + | L _ | LM _ | B -> false + | _ -> true +;; + +let is_var = function V _ -> true | _ -> false;; +let is_lambda = function L _ -> true | _ -> false;; +let is_pacman = function P -> true | _ -> false;; + +let rec subst level delift sub p = + function + | V v -> p, if v = level + fst sub then lift level (snd sub) else V (if delift && v > level then v-1 else v) + | L t -> let p, t = subst (level + 1) delift sub p t in p, L t + | A (t1,t2) -> + let p, t1 = subst level delift sub p t1 in + let p, t2 = subst level delift sub p t2 in + if t1 = B || t2 = B then p, B else + if level = 0 then mk_app p t1 t2 else p, A (t1, t2) + | LM (ts, liftno, id) -> + let p, ts = + let rec aux p = function + | [] -> p, [] + | t::ts -> + let p, ts = aux p ts in + let p, t = subst (level+1) delift sub p t in + p, t::ts in + aux p ts in + p, LM(ts, liftno, id) + | B -> p, B + | P -> p, P +and mk_app p t1 t2 = let t1 = if t1 = P then L P else t1 in match t1 with + | L t1 -> + let p = if is_inert t2 && not (is_var t2) && free_in 0 t1 then {p with conv=t2::p.conv} else p in + subst 0 true (0, t2) p t1 + | LM(ts,liftno,id) -> + let p, t = mk_apps p t2 (List.map (lift ~-1) ts) in + if t = B + then p, B + else + let p, cont = freshvar p in + let newvar = V cont in + let p = add_to_match p id (t,newvar) in + p, newvar + | B + | _ when t2 = B -> p, B + | t1 -> p, A (t1, t2) +and mk_apps p t = + function + | [] -> p, t + | t'::ts -> let p, t = mk_app p t t' in mk_apps p t ts +and lift n = function + | V m -> V (m + n) + | L t -> L (lift n t) + | A (t1, t2) -> A (lift n t1, lift n t2) + | LM (ts, liftno, id) -> LM (List.map (lift n) ts, n + liftno, id) + | B -> B + | P -> P + ;; + +let subst = subst 0 false;; + +let mk_lambda t = L (lift 1 t) ;; + +let subst_many sub = + let rec aux p = function + | [] -> p, [] + | t::tms -> + let p, t = subst sub p t in + let p, tms = aux p tms in + p, t :: tms + in aux +;; + +let rec subst_in_matches sub p = + function + | [] -> p, [] + | (v, branches) :: ms-> + let a, b = List.split branches in + let p, a = subst_many sub p a in + let p, b = subst_many sub p b in + let branches = List.combine a b in + let p, ms = subst_in_matches sub p ms in + p, (v, branches) :: ms +;; + +let subst_in_problem (sub: var * t) (p: problem) = +(* print_endline ("SUBST IN PROBLEM: " ^ string_of_t p (V (fst sub)) ^ " " ^ string_of_t p (snd sub)); *) + let p', div = subst sub p p.div in + let p = {p' with conv=p.conv} in + let p, conv = subst_many sub p p.conv in + let p, matches = subst_in_matches sub p p.matches in + {p with div=div; conv=conv; matches=matches; sigma=sub::p.sigma} +;; + +(* FIXME *) +let unify_terms p t1 t2 = + match t1 with + | V v -> subst_in_problem (v, t2) p + | _ -> problem_fail p "The collapse of a match came after too many steps :(";; + +let rec unify p = + let rec give_duplicates = + let rec aux' t = function + | [] -> [], None + | (t',c')::ts -> if t = t' then ts, Some c' else ( + let ts, res = aux' t ts in (t',c')::ts, res) in + let rec aux = function + | [] -> [], None + | (t,c)::rest -> ( + match aux' t rest with + | rest, None -> aux rest + | rest, Some c' -> (t,c)::rest, Some (c', c) + ) in + function + | [] -> [], None + | (orig,branches) :: ms -> + match aux branches with + | _, None -> let ms, res = give_duplicates ms in (orig,branches) :: ms, res + | branches', Some subst -> (orig,branches') :: ms, Some subst in + let matches, vars_to_be_unified = give_duplicates p.matches in + let p = {p with matches=matches} in + match vars_to_be_unified with + | None -> p + | Some(t', t) -> + (* print_endline ("> unify " ^ string_of_t p (t') ^ " with " ^ string_of_t p t); *) + unify (unify_terms p t' t) +;; + +let problem_done p = + let all_separated = List.for_all (fun (_, lst) -> List.length lst = 1 || List.for_all (fun (t,_) -> is_var t) lst) p.matches in + all_separated && p.div = B +;; + +exception Done;; + +let sanity p = + (* Sanity checks: *) + if is_lambda p.div || is_pacman p.div then problem_fail p "p.div converged" ; + List.iter (function | B -> problem_fail p "p.conv diverged" | _ -> ()) p.conv; + if not (List.for_all (fun (_, lst) -> List.for_all (fun (t,_) -> is_inert t) lst) p.matches) + then problem_fail p "Lambda in a match: k was not big enough?"; + + (* Remove lambdas from conv TODO remove duplicates *) + let conv = List.filter is_inert p.conv in + let p = {p with conv=conv} in + (* unify! :( *) + let p = unify p in + print_endline (string_of_problem p); + if problem_done p then raise Done else p +;; + +let ignore var n p = +print_endline ( + "--- EAT on " ^ string_of_t p (V var) + ^ " (of:" ^ string_of_int n ^ ")"); + let rec aux m t = + if m = 0 + then lift n t + else L (aux (m-1) t) in + let subst = var, aux n (V var) in + sanity (subst_in_problem subst p) +;; + +let explode' var p = + print_endline ( + "--- EXPLODE on " ^ string_of_t p (V var) + ); + let subst = var, B in + sanity (subst_in_problem subst p) + ;; + +let explode p = + match p.div with + | V var -> explode' var p + | _ -> problem_fail p "premature explosion" +;; + +let step var p = + print_endline ( + "--- STEP on " ^ string_of_t p (V var)); + let subst = var, LM([], 0, var) in + sanity (subst_in_problem subst p) +;; + +let id var p = + print_endline ( + "--- ID on " ^ string_of_t p (V var)); + let subst = var, L(V 0) in + sanity (subst_in_problem subst p) +;; + +let apply var appk p = + print_endline ( + "--- APPLY_CONSTS on " ^ string_of_t p (V var) + ^ " (special_k:" ^ string_of_int appk ^ ")"); + let rec mk_freshvars n p = + if n = 0 + then p, [] + else + let p, vs = mk_freshvars (n-1) p in + let p, v = freshvar p in + p, V(v)::vs in + let p, vars = mk_freshvars appk p in + let p, t = mk_apps p (V 0) (List.map (lift 1) vars) in + let t = L (A (lift 1 (V var), t)) in + let subst = var, t in + sanity (subst_in_problem subst p) +;; + +let perm var n p = + print_endline ( + "--- PERM on " ^ string_of_t p (V var) + ^ " (of:" ^ string_of_int n ^ ")"); + (* let p, v = freshvar p in *) + let rec aux' m t = if m < 0 then t else A(aux' (m-1) t, V m) in + let rec aux m t = + if m = 0 + then aux' (n-1) t + else L (aux (m-1) t) in + let t = aux n (lift n (V var)) in + let subst = var, t in + sanity (subst_in_problem subst p) +;; + +(* TODO: +- cosi' come e' possibile unificare rami di branch solo se vanno -> a variabili, + allo stesso modo e' possibile ignorare dei rami se vanno in variabili, e quelle variabili + vengono sostituite ovunque: con bombe in conv e con pacman in div +*) +(* let forget var n p = + let remove_from_branch p var n = ... in + let p, (tm, c) = remove_from_branch p var n in + print_endline ( + "--- FORGET " ^ string_of_t p tm ^ " from the match of " ^ string_of_t p (V var) + ^ " (of:" ^ string_of_int n ^ ")"); + sanity p +;; *) + +let parse strs = + let dummy_p = {freshno=0; div=V 0; conv=[]; matches=[]; sigma=[]} in + let rec aux level = function + | Parser.Lam t -> L (aux (level + 1) t) + | Parser.App (t1, t2) -> + if level = 0 then snd (mk_app dummy_p (aux level t1) (aux level t2)) + else A(aux level t1, aux level t2) + | Parser.Var v -> V v + in let (tms, free) = Parser.parse_many strs + in (List.map (aux 0) tms, free) +;; + +let magic6 div conv cmds = + print_hline (); + let all_tms, var_names = parse (div :: conv) in + let div, conv = List.hd all_tms, List.tl all_tms in + let freshno = 1 + List.length var_names in + let p = {freshno; div; conv; matches=[]; sigma=[]} in + let p = try + let subst = Util.index_of "BOMB" var_names, L B in + let p = subst_in_problem subst p in p + with Not_found -> p in + let p = sanity p in + try + problem_fail (List.fold_left (|>) p cmds) "Problem not completed" + with + | Done -> () +;; + +let interactive div conv cmds = + print_hline (); + let all_tms, var_names = parse (div :: conv) in + let div, conv = List.hd all_tms, List.tl all_tms in + let freshno = 1 + List.length var_names in + let p = {freshno; div; conv; matches=[]; sigma=[]} in + let p = try + let subst = Util.index_of "BOMB" var_names, L B in + let p = subst_in_problem subst p in p + with Not_found -> p in + let p = sanity p in + let p = List.fold_left (|>) p cmds in + let rec f p cmds = + let nth spl n = int_of_string (List.nth spl n) in + let read_cmd () = + let s = read_line () in + let spl = Str.split (Str.regexp " +") s in + s, let uno = List.hd spl in + try if uno = "explode" then explode + else if uno = "ignore" then ignore (nth spl 1) (nth spl 2) + else if uno = "step" then step (nth spl 1) + else if uno = "perm" then perm (nth spl 1) (nth spl 2) + else if uno = "apply" then apply (nth spl 1) (nth spl 2) + else if uno = "id" then id (nth spl 1) + else failwith "unknown" + with Failure _ -> print_endline "Wrong input."; (fun x -> x) in + let str, cmd = read_cmd () in + let cmds = str::cmds in + try + let p = cmd p in f p cmds + with + | Done -> List.iter print_endline (List.rev cmds) + in f p [] +;; + +let _ = magic6 + "x x" + [ "_. BOMB" ] + [ ignore 1 1; explode ] +;; + + let _ = magic6 + "x y BOMB b" + [ "x BOMB y c" ] + [ perm 1 3; step 1 ; ignore 8 2; explode; ];; + +let _ = magic6 + "x BOMB a1 c" + [ "x y BOMB d"; "x BOMB a2 c" ] + [ perm 1 3 ; step 1 ; step 12; ignore 13 1; explode; ] +;; + +let _ = magic6 + "x (x x)" + [ "x x" ; "x x x" ] [ + apply 1 1; + step 1; + explode; + step 9; +];; + +let _ = magic6 + "x (_.BOMB)" + [ "x (_._. BOMB)" ] + [ apply 1 2; ] +;; + +let _ = magic6 + "x (_.y)" + [ "y (_. x)" ] + [ apply 1 1; ignore 1 1; explode; ] +;; + +let _ = magic6 + "y (x a1 BOMB c) (x BOMB b1 d)" + [ "y (x a2 BOMB c) (x BOMB b1 d)"; + "y (x a1 BOMB c) (x BOMB b2 d)";] + [ 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; ] +;; + +let _ = magic6 + "z (y x)" + [ "z (y (x.x))"; "y (_. BOMB)" ] + [ apply 2 1; step 3; explode' 8; ] +;; + +let _ = magic6 + "y x" + [ "y (x.x)"; "x (_. BOMB)" ] + [ apply 1 1; ignore 2 1; step 1; explode; ] +;; + +let _ = magic6 + "z (y x)" + [ "z (y (x.x))"; "y (_. BOMB)" ] + [ step 1; explode; apply 2 1; id 2; ignore 3 1; ] +;; + +let _ = magic6 + "y (x a)" + [ "y (x b)"; "x BOMB" ] [ + id 2; + step 1; + explode; +];; + +magic6 + "y (x a)" [ "y (x b)"; "x BOMB"; "y a" ] + [ + apply 1 1; + perm 2 2; + perm 2 2; + step 3; + apply 2 1; + ignore 4 1; + step 2; + ignore 12 1; + ignore 13 1; + step 1; + explode; +];; + +interactive + "y (x a)" +[ "y (x b)"; "x BOMB"; "y a" ] [];; + +print_endline "ALL DONE. " diff --git a/ocaml/console.ml b/ocaml/console.ml new file mode 100644 index 0000000..696a74d --- /dev/null +++ b/ocaml/console.ml @@ -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 = [("&", "&"); (">", ">"); ("<", "<"); (""", "\""); ("'", "'")] + 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 '-' / "
") +;; + +let print_heading s = + print_newline (); + print_endline (("# " ^ s) / ("

" ^ html_escape s ^ "

")) +;; + +let print_bullet f = + print_newline (); + print_endline (("- " / "")) +;; + +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 index 0000000..e3b769b --- /dev/null +++ b/ocaml/console.mli @@ -0,0 +1,24 @@ +type fancyobj + +val fancy_of_string: string -> fancyobj + +val (^^) : fancyobj -> fancyobj -> fancyobj +val (/) : string -> string -> fancyobj + + +val print_char : char -> unit +val print_string : string -> unit +val print_string_endline : string -> unit +(* val print_bytes : bytes -> unit *) +val print_int : int -> unit +(* val print_float : float -> unit *) + +val print : fancyobj -> unit +val print_endline : fancyobj -> unit + +val print_newline : unit -> unit + +val print_hline : unit -> unit +val print_heading : string -> unit +val print_bullet : fancyobj -> unit +val print_math : string -> unit diff --git a/ocaml/discriminator.mli b/ocaml/discriminator.mli new file mode 100644 index 0000000..44ba167 --- /dev/null +++ b/ocaml/discriminator.mli @@ -0,0 +1,6 @@ +module type Discriminator = sig + type t + val magic: string list -> string list -> t + val magic_conv: div:(string option) -> conv:string list -> nums:string list -> string list -> t + val main: t list -> unit +end diff --git a/ocaml/lambda3.ml b/ocaml/lambda3.ml new file mode 100644 index 0000000..f61e1e5 --- /dev/null +++ b/ocaml/lambda3.ml @@ -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 "------- ------"; + 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 "-------------------"; + 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 "------------------"; + 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 "------------------"; +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 "-----------------"; + 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 "-------- --------" + ) 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 index 0000000..39e77a7 --- /dev/null +++ b/ocaml/lambda3.ml.ar @@ -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 "------- ------"; + 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 "-------------------"; + 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 "------------------"; + 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 "------------------"; +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 "-----------------"; + 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 "-------- --------" + ) 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 index 0000000..cbaf41c --- /dev/null +++ b/ocaml/lambda3.mli @@ -0,0 +1 @@ +include Discriminator.Discriminator diff --git a/ocaml/lambda4.ml b/ocaml/lambda4.ml new file mode 100644 index 0000000..dbd7396 --- /dev/null +++ b/ocaml/lambda4.ml @@ -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 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 ("------- ------\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 "-------------------"; + 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 "------------------"; + 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 "------------------"; +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 "-----------------"; + (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 "-------- --------" + ) 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 index 0000000..cbaf41c --- /dev/null +++ b/ocaml/lambda4.mli @@ -0,0 +1 @@ +include Discriminator.Discriminator diff --git a/ocaml/listx.ml b/ocaml/listx.ml new file mode 100644 index 0000000..ecc8a92 --- /dev/null +++ b/ocaml/listx.ml @@ -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 index 0000000..97226ae --- /dev/null +++ b/ocaml/listx.mli @@ -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 index 0000000..a29f203 --- /dev/null +++ b/ocaml/mk_andrea @@ -0,0 +1,3 @@ +ocamlc -c parser.ml +ocamlc -o andrea andrea.ml parser.cmo +./andrea diff --git a/ocaml/num.ml b/ocaml/num.ml new file mode 100644 index 0000000..6f3cae5 --- /dev/null +++ b/ocaml/num.ml @@ -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 index 0000000..6a11731 --- /dev/null +++ b/ocaml/num.ml.ar @@ -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 index 0000000..2f92884 --- /dev/null +++ b/ocaml/num.mli @@ -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 : [ 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 index 0000000..46bf51e --- /dev/null +++ b/ocaml/num.mli.ar @@ -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 : [ 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 index 0000000..b958ed5 --- /dev/null +++ b/ocaml/numx.ml @@ -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 index 0000000..206c32f --- /dev/null +++ b/ocaml/numx.mli @@ -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 index 0000000..4c7b829 --- /dev/null +++ b/ocaml/parser.ml @@ -0,0 +1,153 @@ +type term = + | Var of int + | App of term * term + | Lam of term +;; + +let mk_app x y = App(x, y);; +let mk_lam x = Lam x;; +let mk_var x = Var x;; + +exception ParsingError of string;; + +let isAlphaNum c = let n = Char.code c in 48 <= n && n <= 122 ;; +let isSpace c = c = ' ' || c = '\n' || c = '\t' ;; + +let rec index_of x = + function + | [] -> raise (Failure "index_of: Not Found") + | h::t -> if x = h then 0 else 1 + index_of x t +;; +(* FIXME *) +let mk_var' (bound, free) x = + if List.mem x bound + then free, mk_var (index_of x bound) + else if List.mem x free + then free, mk_var (List.length bound + index_of x free) + else (free @ [x]), mk_var (List.length bound + List.length free) +;; + +let mk_app' = function + | [] -> raise (ParsingError "bug") + | t :: ts -> List.fold_left mk_app t ts +;; + +let explode s = + let rec aux i l = + if i < 0 then l else aux (i - 1) (s.[i] :: l) + in aux (String.length s - 1) [] +;; + +let implode l = + let res = String.create (List.length l) in + let rec aux i = function + | [] -> res + | c :: l -> res.[i] <- c; aux (i + 1) l in + aux 0 l +;; + +let rec strip_spaces = function + | c::cs when isSpace c -> strip_spaces cs + | cs -> cs +;; + +let read_var s = + let rec aux = function + | [] -> None, [] + | c::cs as x -> if isAlphaNum c + then match aux cs with + | (Some x), cs' -> Some (c :: x), cs' + | None, cs' -> (Some [c]), cs' + else None, x + in match aux s with + | None, y -> None, y + | Some x, y -> Some (implode x), y +;; + +let read_var' (bound, free as vars) s = + match read_var s with + | Some varname, cs -> + let free, v = mk_var' vars varname in + Some [v], cs, (bound, free) + | _, _ -> raise (ParsingError ("Can't read variable")) +;; + +let rec read_smt vars = + let check_if_lambda cs = match read_var cs with + | None, _ -> false + | Some x, cs -> match strip_spaces cs with + | [] -> false + | c::_ -> c = '.' + in let read_lambda (bound, free) cs = ( + match read_var (strip_spaces cs) with + | Some varname, cs -> + let vars' = (varname::bound, free) in + (match strip_spaces cs with + | [] -> raise (ParsingError "manca dopo variabile lambda") + | c::cs -> (if c = '.' then (match read_smt vars' cs with + | None, _, _ -> raise (ParsingError "manca corpo lambda") + | Some [x], y, (_, free) -> Some [mk_lam x], y, (bound, free) + | Some _, _, _ -> raise (ParsingError "???") + ) else raise (ParsingError "manca . nel lambda") + )) + | _, _ -> assert false + ) in let rec aux vars cs = + match strip_spaces cs with + | [] -> None, [], vars + | c::_ as x -> + let tms, cs, vars = ( + if c = '(' then read_pars vars x + else if c = ')' then (None, x, vars) + else if check_if_lambda x then read_lambda vars x + else read_var' vars x) in + match tms with + | Some [tm] -> ( + match aux vars cs with + | None, cs, vars -> Some [tm], cs, vars + | Some ts, cs, vars -> Some (tm :: ts), cs, vars + ) + | Some _ -> raise (ParsingError "bug") + | None -> None, x, vars + in fun cs -> match aux vars cs with + | None, cs, vars -> None, cs, vars + | Some ts, cs, vars -> Some [mk_app' ts], cs, vars +and read_pars vars = function + | [] -> None, [], vars + | c::cs -> if c = '(' then ( + let tm, cs, vars = read_smt vars cs in + let cs = strip_spaces cs in + match cs with + | [] -> None, [], vars + | c::cs -> if c = ')' then tm, cs, vars else raise (ParsingError ") mancante") + ) else raise (ParsingError "???") +;; + +let parse x = + match read_smt ([],[]) (explode x) with + | Some [y], [], _ -> y + | _, _, _ -> raise (ParsingError "???") +;; + +let var_zero = "ω";; (* w is an invalid variable name *) + +let parse_many strs = + let f (x, y) z = match read_smt y (explode z) with + | Some[tm], [], vars -> (tm :: x, vars) + | _, _, _ -> raise (ParsingError "???") + in let aux = List.fold_left f ([], ([], [var_zero])) (* index zero is reserved *) + in let (tms, (_, free)) = aux strs + in (List.rev tms, free) +;; + +(********************************************************************** + +let rec string_of_term = function + | Tvar n -> string_of_int n + | Tapp(t1, t2) -> "(" ^ string_of_term t1 ^ " " ^ string_of_term t2 ^ ")" + | Tlam(t1) -> "(\\" ^ string_of_term t1 ^ ")" +;; + +let _ = prerr_endline (">>>" ^ string_of_term (parse "(\\x. x y z z1 k) z1 z j"));; + + +**********************************************************************) diff --git a/ocaml/parser.mli b/ocaml/parser.mli new file mode 100644 index 0000000..c073c3a --- /dev/null +++ b/ocaml/parser.mli @@ -0,0 +1,9 @@ +type term = + | Var of int + | App of term * term + | Lam of term + +(* parses a string to a term *) +val parse: string -> term +(* parse many strings/terms, and returns the list of parsed terms + the list of free variables; variable 0 is not used *) +val parse_many: string list -> term list * string list diff --git a/ocaml/problems.ml b/ocaml/problems.ml new file mode 100644 index 0000000..6fb7b43 --- /dev/null +++ b/ocaml/problems.ml @@ -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 index 0000000..e69de29 diff --git a/ocaml/pure.ml b/ocaml/pure.ml new file mode 100644 index 0000000..78c6c4c --- /dev/null +++ b/ocaml/pure.ml @@ -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 index 0000000..f360074 --- /dev/null +++ b/ocaml/pure.mli @@ -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 index 0000000..2f6017a --- /dev/null +++ b/ocaml/test.ml @@ -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 index 0000000..424ec72 --- /dev/null +++ b/ocaml/test1.ml @@ -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 index 0000000..a4af2dd --- /dev/null +++ b/ocaml/util.ml @@ -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 index 0000000..751225a --- /dev/null +++ b/ocaml/util.mli @@ -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 -- 2.39.2