From 55700f849759b51618eaed297344fb9119e53fe5 Mon Sep 17 00:00:00 2001 From: Date: Mon, 12 Jun 2017 22:41:31 +0200 Subject: [PATCH] Initial commit from my pc --- ocaml/Makefile | 4 +- ocaml/andrea3.ml | 116 +++++-- ocaml/andrea3.mli | 1 + ocaml/andrea4'.ml | 358 ++++++++++++++++++++ ocaml/andrea4.ml | 637 +++++++++++++++++++++++++++++++++++ ocaml/andrea6.ml | 405 +++++++++++++++-------- ocaml/andrea7.ml | 751 ++++++++++++++++++++++++++++++++++++++++++ ocaml/lambda4.ml | 309 ++++++++++++++--- ocaml/lambda4b.ml | 821 ++++++++++++++++++++++++++++++++++++++++++++++ ocaml/measure.ml | 32 ++ ocaml/num.ml | 12 +- ocaml/num.mli | 2 +- ocaml/ptest.ml | 16 + ocaml/tmp.ml | 38 +++ 14 files changed, 3283 insertions(+), 219 deletions(-) create mode 100644 ocaml/andrea3.mli create mode 100644 ocaml/andrea4'.ml create mode 100644 ocaml/andrea4.ml create mode 100644 ocaml/andrea7.ml create mode 100644 ocaml/lambda4b.ml create mode 100644 ocaml/measure.ml create mode 100644 ocaml/ptest.ml create mode 100644 ocaml/tmp.ml diff --git a/ocaml/Makefile b/ocaml/Makefile index 3310c6e..b97d5af 100644 --- a/ocaml/Makefile +++ b/ocaml/Makefile @@ -13,8 +13,8 @@ test.out: $(UTILS) lambda3.cmx test1.ml test34.out: $(UTILS) lambda3.cmx lambda4.cmx test.ml $(OCAMLC) -o test34.out $(LIB) $^ -andrea.out: $(UTILS) a.out andrea6.ml - $(OCAMLC) -o andrea.out $(LIB) $(UTILS) andrea6.ml +andrea.out: $(UTILS) a.out andrea7.ml + $(OCAMLC) -o andrea.out $(LIB) $(UTILS) andrea7.ml #test2.out: $(UTILS) lambda3.ml test2.ml andrea # ocamlc -o test2.out $(LIB) $(UTILS) lambda3.ml andrea4.ml test2.ml diff --git a/ocaml/andrea3.ml b/ocaml/andrea3.ml index 2796107..a09ac42 100644 --- a/ocaml/andrea3.ml +++ b/ocaml/andrea3.ml @@ -47,7 +47,7 @@ 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 string_of_int' n = string_of_int n 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) @@ -70,7 +70,7 @@ let rec string_of_term = 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 string_of_int' n = string_of_int n 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) @@ -96,28 +96,28 @@ in let fancy_of_nf t: Console.fancyobj = let rec print ?(l=[]) = function - `Var n -> Lambda3.print_name l n + `Var n -> Util.Vars.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) ^ "] " ^ + "([" ^ print ~l (t :> Num.nf) ^ + " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Num.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) + | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")" + | `Lam(_,nf) -> + let name = Util.Vars.string_of_var (List.length l) in + "" ^ name ^ "." ^ print ~l:(name::l) (nf : Num.nf) in let rec print_html ?(l=[]) = function - `Var n -> Lambda3.print_name l n + `Var n -> Util.Vars.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) + "(match " ^ print_html ~l (t :> Num.nf) ^ + " with " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " " ^ print_html ~l (Num.lift bs_lift t)) !bs) ^ "..." (* Attenzion non sto stampando gli argomenti applicati! Perche' non ce ne sono mai *) + | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print_html ~l) args)) ^ ")" + | `Lam(_,nf) -> + let name = Util.Vars.string_of_var (List.length l) in + "λ" ^ name ^ ". " ^ print_html ~l:(name::l) (nf : Num.nf) in print t / print_html t ;; @@ -235,29 +235,29 @@ let stupid_sort_uniq l = stupid_uniq (List.sort stupid_compare l);; - 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 crea_match k subs (acc : (term * Num.nf) list) : term -> Num.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 + try `N (Util.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))) + if a = 0 then `Lam (true, 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 = List.map (Num.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 branches = List.map (fun t2 -> (Util.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 `Lam (true, `Match(body, lift, bs, args)) ) ) in aux ;; @@ -270,14 +270,43 @@ let mk_zeros k = ;; let is_scott_n t n = - let open Lambda3 in let open Pure in + let open Pure.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 + | L (L (A (V 0, t))) -> assert (n > 0); aux (n-1) t | _ -> assert false in aux n t ;; +let pure_subst delift_by_one what with_what = + let open Pure.Pure in + 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 pure_whd = + let open Pure.Pure in + function + | A(t1, t2) -> + let t2 = pure_whd t2 in + let t1 = pure_whd t1 in + (match t1 with + | L f -> pure_whd (pure_subst true 0 t2 f) + | V _ + | A _ -> A(t1,t2)) + | V _ + | L _ as t -> t +;; + (* do the magic *) let magic strings k h = ( let tms = parse strings @@ -309,29 +338,48 @@ let magic strings k h = ( 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 ps, _ = Num.parse' strings + in let ps = List.map (fun x -> Num.mk_app x (`Var 1010)) ps + in let ps = List.map (fun t -> Num.ToScott.t_of_nf (t :> Num.nf)) ps in let sigma = List.map ( - function (Tvar(n,_,_), inst) -> n, ToScott.t_of_nf inst | _ -> assert false + function (Tvar(n,_,_), inst) -> n, Num.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 + 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 + (* assert (Pure.whd n = Scott.mk_n (Util.index_of (List.nth tms' i) subs))) ps *) + assert (is_scott_n (pure_whd n) (Util.index_of (List.nth tms' i) subs))) ps in let _ = progress "fatto." in () );; +let no_subterms 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 subno = List.length subs + in let _ = progress ("sottotermini generati: " ^ string_of_int subno) + in subno +;; + 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 +no_subterms tms k h ;; let _ = @@ -345,7 +393,7 @@ let _ = 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 + no_subterms tms k h ;; (* type var' = (* unique name *) int * (int * term') option * (*dead*) bool option diff --git a/ocaml/andrea3.mli b/ocaml/andrea3.mli new file mode 100644 index 0000000..8ec0c9f --- /dev/null +++ b/ocaml/andrea3.mli @@ -0,0 +1 @@ +val do_everything: string list -> int diff --git a/ocaml/andrea4'.ml b/ocaml/andrea4'.ml new file mode 100644 index 0000000..f734cca --- /dev/null +++ b/ocaml/andrea4'.ml @@ -0,0 +1,358 @@ +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;; +let dummy = Tvar 333;; + + +(* 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, false) +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 -> Tvar (n-1) + | Tapp(t1, t2, b) -> Tapp(minus1 t1, minus1 t2, b) + | Tlam(n, t) -> Tlam(n-1, minus1 t) + (* in let open Parser *) + in let rec myterm_of_term = function + | Parser.Var n -> Tvar n + | 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 "free" ^ string_of_int n else "bound" ^ string_of_int n in + let rec string_of_var t = + if Tvar t = dummy then "_" else if Tvar t = zero then "ZZ" else match t with + | n -> 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 string_of_int' t + 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 -> Util.Vars.print_name l n + | `N n -> string_of_int n + | `Match(t,bs_lift,bs,args) -> + "([" ^ print ~l (t :> Num.nf) ^ + " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Num.lift bs_lift t)) !bs) ^ "] " ^ + String.concat " " (List.map (print ~l) args) ^ ")" + | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")" + | `Lam(_,nf) -> + let name = Util.Vars.string_of_var (List.length l) in + "" ^ name ^ "." ^ print ~l:(name::l) (nf : Num.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 t +;; + +let print_term t = print_endline (fancy_of_term t :> Console.fancyobj);; +(* *) + + +let varcount = ref 11;; + +let freshvar () = ( + varcount := (!varcount + 1); + !varcount +);; + + + +(* magic ["x (x x x)"; "x (y. y x)"; "x x (y. y y (x x y))"] ;; *) +(* magic ["((x x) (x. x))";"x x"];; *) + +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 bullet = ">" / "•" *) + (* in let progress s = print_endline (bullet ^^ fancy_of_string s) *) + in let progress = print_h1 + 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 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 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/andrea4.ml b/ocaml/andrea4.ml new file mode 100644 index 0000000..4b7e448 --- /dev/null +++ b/ocaml/andrea4.ml @@ -0,0 +1,637 @@ +(* type var = (* unique name *) int * (int * term) option * (*level*) int *) +type term = + | Tvar of int + | Tapp of term * term * bool + | Tlam of int * term +;; + +let zero = Tvar 1010;; +let dummy = Tvar 333;; + + +(* 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, false) +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 -> Tvar (n-1) + | Tapp(t1, t2, b) -> Tapp(minus1 t1, minus1 t2, b) + | Tlam(n, t) -> Tlam(n-1, minus1 t) + (* in let open Parser *) + in let rec myterm_of_term = function + | Parser.Var n -> Tvar n + | 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 "free" ^ string_of_int n else "bound" ^ string_of_int n in + let rec string_of_var t = + if Tvar t = dummy then "_" else if Tvar t = zero then "ZZ" else match t with + | n -> 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 string_of_int' t + 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 -> Util.Vars.print_name l n + | `N n -> string_of_int n + | `Match(t,bs_lift,bs,args) -> + "([" ^ print ~l (t :> Num.nf) ^ + " ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Num.lift bs_lift t)) !bs) ^ "] " ^ + String.concat " " (List.map (print ~l) args) ^ ")" + | `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")" + | `Lam(_,nf) -> + let name = Util.Vars.string_of_var (List.length l) in + "" ^ name ^ "." ^ print ~l:(name::l) (nf : Num.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 t +;; + +let print_term t = print_endline (fancy_of_term t :> Console.fancyobj);; +(* *) + + +let varcount = ref 11;; + +let freshvar () = ( + varcount := (!varcount + 1); + !varcount +);; + +let find_applicative = + let rec aux = function + | Tapp(t1, Tlam _, _) -> Some t1 + | Tapp(t1, t2, _) -> + (match aux t1 with + | None -> aux t2 + | _ as r -> r) + | _-> None + in let rec aux2 = function + | [] -> None + | x::xs -> (match aux x with + | None -> aux2 xs + | _ as result -> result + ) + in aux2 +;; + +let mk_apps t ts = List.fold_right (fun x y -> mk_app y x) (List.rev ts) t;; (* which FOLD? FIXME *) + +let rec hd = function | Tvar _ as x -> x | Tapp(t, _, _) -> hd t | _ -> assert false;; + +let rec set_applied = + function + | Tvar _ as v -> v + | Tlam _ -> assert false + | Tapp(t1,t2,_) -> Tapp(set_applied t1, set_applied t2, true) +;; + +let rec constant a n = + if n = 0 then [] else a:: (constant a (n-1)) +;; + +let rec mk_dummies k t = + set_applied (mk_apps t (constant dummy (k+1))) +;; + +let rec make_lambda_zero k = + if k = 0 then mk_dummies (k+1) zero else Tlam(0, make_lambda_zero (k-1)) +;; + +let mk_vars n = + let rec aux n = + if n = 0 + then [] + else (Tvar (freshvar ())) :: (aux (n-1)) + in aux n @ [make_lambda_zero (n+1)] +;; + +let apply a vars = + let rec aux = function + | Tapp(t1, t2, b) -> + if t1 = a + then (assert (not b); Tapp(aux t1, mk_apps' t2 vars, true)) + else Tapp(aux t1, aux t2, b) + | _ as t -> t + and mk_apps' t vars = + if t = zero + then mk_dummies (List.length vars - 1) t + else aux (mk_apps t vars) + in aux +;; + +let round k (app_map, tms) = + match find_applicative tms with + | None -> raise Not_found + | Some a -> + let vars = mk_vars k in + let f = apply a vars in + let app_map = (a, vars) :: (List.map (fun (x,y) -> f x, y) app_map) + in (app_map, List.map f tms) +;; + +let ends_with t1 t2 = match t1 with + | Tapp(_, t, _) -> t = t2 + | _ -> false +;; + +let rec last_round k (app_map, forbidden, t) = + let mk_apps' forbidden t vars = + if List.mem t forbidden + then mk_dummies (List.length vars - 1) t + else mk_apps t vars + (* in let rec already_applied = function + | Tapp(_, t) -> t = zero || t = dummy || hd t = zero + | _ -> false *) + in if ends_with t dummy then (app_map, forbidden, t) else (match t with + | Tapp(t1, t2, b) -> + if b + then + let app_map, forbidden, t1 = last_round k (app_map, forbidden, t1) + in let app_map, forbidden, t2 = last_round k (app_map, forbidden, t2) + in app_map, forbidden, Tapp(t1, t2, b) + else + let app_map, forbidden, t1 = last_round k (app_map, forbidden, t1) + in let app_map, forbidden, t2 = + try + let vars = List.assoc t1 app_map + in last_round k (app_map, forbidden, (mk_apps' forbidden t2 vars)) + with Not_found -> + let vars = mk_vars k in + let app_map = (t1, vars) :: app_map in + last_round k (app_map, (vars @ forbidden), (mk_apps' forbidden t2 vars)) + in app_map, forbidden, Tapp(t1, t2, true) + | _ as t -> app_map, forbidden, t + ) +;; + +let fixpoint f = + let rec aux x = try + let y = f x in aux y + with Not_found -> x + in aux +;; + +(* lista di sottotermini applicativi *) +let rec subterms = function + | Tlam _ -> assert false + | Tvar _ as v -> [v] + | Tapp(t1, t2, b) -> Tapp(t1, t2, b) :: ((subterms t1) @ (subterms t2)) +;; + +(* filtra dai sottotermini le variabili *) +let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;; + +let stupid_sort_uniq map l = + let rec stupid_uniq = function + | [] -> [] + | x::xs -> if List.mem x xs then (stupid_uniq xs) else x::(stupid_uniq xs) + in let stupid_compare a b = + let rec size = function + | Tvar n as v -> if v = zero then 0 else ( + try + let t, _ = List.find (fun (_,vars) -> List.mem v vars) map + in 1 + size t + with Not_found -> 1 + n) + | Tapp(t1,t2,_) -> 1 + size t1 + size t2 + | Tlam _ -> assert false + in compare (size a) (size b) + in 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 subs map forbidden (acc : (term * Num.nf) list) : term -> Num.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,true)) subs) subs + in if cont = [] then + try `N (Util.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else + + if List.mem (hd t1) forbidden then `Lam (true,req (Tapp(t1, dummy, true))) + else ( + let vars = List.assoc t1 map + (* 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 (Num.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 -> (Util.index_of t2 subs, req (Tapp(t1, t2, true)))) cont + in let bs = ref(branches) + in let lift = 1 + in let args = [] + in `Lam (true, `Match(body, lift, bs, args)) + ) + ) in aux +;; + +(* filtra dai sottotermini le variabili *) +let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;; + +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 rec freevars = function + | Tvar _ as v -> [v] + | Tlam(v,t) -> List.filter (fun x-> x <> Tvar v) (freevars t) + | Tapp(t1,t2,_) -> (freevars t1) @ (freevars t2) +;; + +open Pure;; + +let is_scott_n t n = + let open Lambda4 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 +;; +let is_scott = + let open Lambda4 in let open Pure in + let rec aux = function + | L (L (A (V 1, L (V 0)))) -> 0 + | L (L (A (V 0, t))) -> 1 + aux t + | _ -> assert false + in aux +;; + +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 magic strings = + let rec map_helper_3 a b f = + function + | [] -> a, b, [] + | c::cs -> + let a, b, d = f (a, b, c) in + let a, b, ds = map_helper_3 a b f cs in + a, b, (d::ds) + in let _ = print_hline () + in let tms = parse strings + in let k = compute_special_k tms + in let zero' = make_lambda_zero (k+1) + in let tms = List.map (fun x -> Tapp(x, zero', false)) tms + in let fv = Util.sort_uniq (List.concat (List.map freevars tms)) + in let (map, tms') = fixpoint (round k) ([], tms) + (* in let _ = print_string_endline "map1 "; List.iter (fun (t,_) -> print_term t) map; print_string_endline "ok1" *) + in let _ = List.map print_term tms' + + in let map1 = List.map fst map + in let map2 = List.map snd map + in let map_new, forbidden, map1' = map_helper_3 [] [zero] (last_round k) map1 + + in let map = map_new @ (List.combine map1' map2) + (* in let _ = print_string_endline "map2 "; List.iter (fun (t,_) -> print_term t) map; print_string_endline "ok2" *) + in let map, forbidden, tms' = map_helper_3 map forbidden (last_round k) tms' + + in let _ = List.map print_term tms' + in let subs = List.concat (List.map subterms tms') + in let subs = stupid_sort_uniq map 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 _ = print_string_endline " subs"; List.iter print_term subs *) + (* in let _ = print_string_endline "map "; List.iter (fun (t,_) -> print_term t) map; print_string_endline "ok" *) + + in let f t acc = let res = crea_match subs map forbidden 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 _ = List.iter (fun (x,y) -> print_endline (fancy_of_term x ^^ (" : " / " ↦ ") ^^ fancy_of_nf y)) sigma + + in let _ = print_string_endline "controllo di purezza"; + (* in let open Num *) + in let ps, _ = Num.parse' strings + in let ps = List.map (fun x -> Num.mk_app x (`Var 1010)) ps + in let ps = List.map (fun t -> Num.ToScott.t_of_nf (t :> Num.nf)) ps + in let sigma = List.map ( + function (Tvar n , inst) -> n, Num.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 ("X " ^ Pure.print (Pure.whd n)); + (* assert (is_scott_n (Pure.whd n) (Lambda3.index_of (List.nth tms' i) subs)) *) + is_scott (Pure.whd n); () + ) ps *) + in () +;; + + +(* magic ["x (x x x)"; "x (y. y x)"; "x x (y. y y (x x y))"] ;; *) +magic ["((x x) (x. x))";"x x"];; + +(* + +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 bullet = ">" / "•" *) + (* in let progress s = print_endline (bullet ^^ fancy_of_string s) *) + in let progress = print_h1 + 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 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 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/andrea6.ml b/ocaml/andrea6.ml index 34c0788..38346b0 100644 --- a/ocaml/andrea6.ml +++ b/ocaml/andrea6.ml @@ -16,10 +16,11 @@ type t = type problem = { - freshno : int - ; div : t + orig_freshno: int + ; freshno : int + ; div : t list ; conv : t list - ; matches : (var (* variable originating this match *) * (t (* term to discriminate *) * t (* continuation *)) list) list + ; matches : (var (* variable originating this match *) * (bool (* term comes from div*) * (t (* term to discriminate *) * t (* continuation *))) list) list ; sigma : (var * t) list (* substitutions *) } @@ -35,19 +36,40 @@ let string_of_t p = in aux 0 ;; +let string_of_t p = + let bound_vars = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"] in + let rec string_of_term_w_pars level = function + | V v -> if v >= level then "`" ^ string_of_int (v-level) else List.nth bound_vars (level - v-1) + | A _ as t -> "(" ^ string_of_term_no_pars_app level t ^ ")" + | L _ as t -> "(" ^ string_of_term_no_pars_lam level t ^ ")" + | LM (ts,liftno,id) -> "[match orig="^ string_of_term_w_pars 0 (V id)^"]" + | B -> "BOT" + | P -> "PAC" + and string_of_term_no_pars_app level = function + | A(t1,t2) -> (string_of_term_no_pars_app level t1) ^ " " ^ (string_of_term_w_pars level t2) + | _ as t -> string_of_term_w_pars level t + and string_of_term_no_pars_lam level = function + | L t -> "λ" ^ string_of_term_w_pars (level+1) (V 0) ^ ". " ^ (string_of_term_no_pars_lam (level+1) t) + | _ as t -> string_of_term_no_pars level t + and string_of_term_no_pars level = function + | L _ as t -> string_of_term_no_pars_lam level t + | _ as t -> string_of_term_no_pars_app level t + in string_of_term_no_pars 0 +;; + let string_of_problem p = let lines = [ - "[DV] " ^ string_of_t p p.div; + "[DV] " ^ String.concat "\n " (List.map (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 + (* "" ; *) + ] @ Util.concat_map (fun (v, lst) -> ("[<>] of "^(string_of_t p (V v))) :: List.map (fun (b,(t,c)) -> " " ^ (if b then "*" else " ") ^ " " ^ string_of_t p t (* ^" -> " ^ 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 "!!!!!!!!!!!!!!! FAIL !!!!!!!!!!!!!!!"; print_endline (string_of_problem p); failwith reason ;; @@ -62,10 +84,10 @@ let add_to_match p id entry = List.map (fun (id',lst as x) -> if id <> id' then x else (id, entry::lst) ) p.matches with | Not_found -> (id,[entry]) :: p.matches in - {p with matches=matches} + {p with matches} ;; -let free_in v = +let var_occurs_in v = let rec aux level = function | V v' -> v + level = v' | A(t1,t2) -> (aux level t1) || (aux level t2) @@ -79,73 +101,78 @@ let free_in v = let rec is_inert = function | A(t,_) -> is_inert t - | L _ | LM _ | B -> false - | _ -> true + | V _ -> true + | L _ | LM _ | B | P -> false ;; 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 = +let rec subst isdiv 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 + | L t -> let p, t = subst isdiv (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 + let p, t1 = subst isdiv level delift sub p t1 in + let p, t2 = subst isdiv 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) + if level = 0 then mk_app isdiv 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 + let p, t = subst isdiv (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 +and mk_app isdiv 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 + (* FIXME BUG HERE! *) + if is_inert t2 && (match t2 with V v -> v > p.orig_freshno | _ -> true ) && not (var_occurs_in 0 t1) + then (if isdiv then {p with div=p.div @ [t2]} else {p with conv=p.conv @ [t2]}), lift (-1) t1 + else subst isdiv 0 true (0, t2) p t1 | LM(ts,liftno,id) -> - let p, t = mk_apps p t2 (List.map (lift ~-1) ts) in + let p, t = mk_apps isdiv 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 + let p = add_to_match p id (isdiv,(t,newvar)) in p, newvar | B | _ when t2 = B -> p, B | t1 -> p, A (t1, t2) -and mk_apps p t = +and mk_apps isdiv 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 + | t'::ts -> let p, t = mk_app isdiv p t t' in mk_apps isdiv p t ts + and lift n = + let rec aux n' = + function + | V m -> V (if m >= n' then m + n else m) + | L t -> L (aux (n'+1) t) + | A (t1, t2) -> A (aux n' t1, aux n' t2) + | LM (ts, liftno, id) -> LM (List.map (aux (n'+1)) ts, n + liftno, id) + | B -> B + | P -> P + in aux 0 ;; -let subst = subst 0 false;; +let subst isdiv = subst isdiv 0 false;; let mk_lambda t = L (lift 1 t) ;; -let subst_many sub = +let subst_many b sub = let rec aux p = function | [] -> p, [] | t::tms -> - let p, t = subst sub p t in + let p, t = subst b sub p t in let p, tms = aux p tms in p, t :: tms in aux @@ -156,8 +183,10 @@ let rec subst_in_matches sub p = | [] -> 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 b, c = List.split b in + let p, b = subst_many false sub p b in + let p, c = subst_many false sub p c in + let b = List.combine b c in let branches = List.combine a b in let p, ms = subst_in_matches sub p ms in p, (v, branches) :: ms @@ -165,11 +194,14 @@ let rec subst_in_matches sub p = 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 div, conv = p.div, p.conv in + let p = {p with div=[]; conv=[]} in + let p, div' = subst_many true sub p div in + let p, conv' = subst_many false sub 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} + let p = {p with div=div'@p.div; conv=conv'@p.conv; matches} in + (* print_endline ("after sub: \n" ^ string_of_problem p); *) + {p with sigma=sub::p.sigma} ;; (* FIXME *) @@ -182,14 +214,14 @@ 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 + | (b',(t',c'))::ts -> if t = t' (* FIXME! eta-eq here *)then ts, Some (b',c') else ( + let ts, res = aux' t ts in (b',(t',c'))::ts, res) in let rec aux = function | [] -> [], None - | (t,c)::rest -> ( + | (b,(t,c))::rest -> ( match aux' t rest with | rest, None -> aux rest - | rest, Some c' -> (t,c)::rest, Some (c', c) + | rest, Some (b',c') -> ((if not b' then false else b),(t,c))::rest, Some (c', c) ) in function | [] -> [], None @@ -207,72 +239,120 @@ let rec unify p = ;; 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 + 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 && List.exists ((=) B) p.div +;; + +let free_vars p t = + let rec aux level = function + | V v -> if v >= level then [v] else [] + | A(t1,t2) -> (aux level t1) @ (aux level t2) + | L t -> aux (level+1) t + | LM(ts,_,id) -> (List.concat (List.map (aux level) ts)) @ ( + let lst = List.assoc id p.matches in + List.concat (List.map (fun (_,(t1,t2)) -> (aux 0 t1) @ (aux 0 t2)) lst) + ) + | B -> [] + | P -> [] + in Util.sort_uniq (aux 0 t) +;; + +let visible_vars p t = + let rec aux = function + | V v -> [v] + | A(t1,t2) -> (aux t1) @ (aux t2) + | L t -> [] + | LM(ts,_,id) -> (List.concat (List.map aux ts)) @ ( + let lst = List.assoc id p.matches in + List.concat (List.map (fun (_,(t1,t2)) -> (aux t1) @ (aux t2)) lst) + ) + | B -> [] + | P -> [] + in Util.sort_uniq (aux t) +;; + +let forget_variable var p = + let p', div = subst_many true (var, P) p p.div in + let p = {p' with conv=p.conv} in + let p, conv = subst_many false (var, B) p p.conv in + let p, matches = subst_in_matches (var, B) p p.matches in + {p with div; conv; matches; sigma=p.sigma} +;; +let rec remove_divergent_discriminators p = + let f = fun (b,(t,_)) -> b && (t = B || is_lambda t) in + try + let v,l = List.find (fun (_,lst) -> List.exists f lst) p.matches in + let (_,(_,c)) as entry = List.find f l in + let l = List.filter ((<>) entry) l in + let matches = List.map (fun (v', l') -> v', if v' = v then l else l') p.matches in + let vars = free_vars p c in + let p = {p with matches} in + List.fold_right forget_variable vars p + with Not_found -> p ;; exception Done;; let sanity p = + (* try to fix divergent discriminators *) + let p = remove_divergent_discriminators p in + (* Remove lambdas from conv TODO remove duplicates *) + let div = List.filter (function | P | L _ -> false | _ -> true) p.div in + let conv = List.filter (function | B | V _ | A _ -> true | _ -> false) p.conv in + let p = {p with div;conv} in (* 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?"; + if p.div = [] then problem_fail p "p.div converged"; + if List.mem B p.conv then problem_fail p "p.conv diverged"; + if not (List.for_all (fun (_, lst) -> List.for_all (fun (b,(t,_)) -> is_inert t) lst) p.matches) + then problem_fail p "Unsolvable discrimination"; - (* 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); + print_endline (string_of_problem p); (* non cancellare *) if problem_done p then raise Done else p ;; +let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);; + let ignore var n p = -print_endline ( - "--- EAT on " ^ string_of_t p (V var) - ^ " (of:" ^ string_of_int n ^ ")"); + print_cmd "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 + let p, fresh = freshvar p in + let subst = var, aux n (V fresh) 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 + let fv1 = List.concat (List.map (visible_vars p) p.div) in + let fv2 = List.concat (List.map (visible_vars p) p.conv) in + let fv = List.filter (fun x -> not (List.mem x fv2)) fv1 in + let fv = List.filter ((<) p.orig_freshno) fv in + match fv with + | var::_ -> + print_cmd "EXPLODE" ("on " ^ string_of_t p (V var)); + let subst = var, B in + sanity (subst_in_problem subst p) | _ -> problem_fail p "premature explosion" ;; let step var p = - print_endline ( - "--- STEP on " ^ string_of_t p (V var)); + print_cmd "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)); + print_cmd "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 ^ ")"); + print_cmd "APPLY" + (string_of_t p (V var) ^ " applies no." ^ string_of_int appk ^ " fresh variables"); let rec mk_freshvars n p = if n = 0 then p, [] @@ -281,23 +361,21 @@ let apply var appk p = 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 p, t = mk_apps false 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 *) + print_cmd "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 t = aux n (lift n (V v)) in let subst = var, t in sanity (subst_in_problem subst p) ;; @@ -307,33 +385,51 @@ let perm var n p = 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 forget var no p = + try + let l = List.assoc var p.matches in + let (b,(tm,c)) = List.nth l no in + let l = List.mapi (fun n x -> if n = no then (b,(B,c)) else x) l in + let matches = List.map (fun (v,lst) -> v, if v = var then l else lst) p.matches in + let p = {p with matches} in + print_cmd "FORGET" (string_of_t p tm ^ " from the match of " ^ string_of_t p (V var)); + sanity p + (* (match c with + | V var -> + print_endline ( + "--- FORGET " ^ string_of_t p tm ^ " from the match of " ^ string_of_t p (V var)); + let p = forget_variable var p in + + | _ -> print_endline "too late to forget that term"; p + ) *) + with Failure "nth" -> + print_endline "wtf?"; p +;; let parse strs = - let dummy_p = {freshno=0; div=V 0; conv=[]; matches=[]; sigma=[]} in + let dummy_p = {orig_freshno=0; freshno=0; div=[]; 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)) + if level = 0 then snd (mk_app false 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 rec list_split n = + function + | [] -> [], [] + | x::xs as l -> if n = 0 then [], l else let a, b = list_split (n-1) xs in x::a, b +;; + 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 all_tms, var_names = parse (div @ conv) in + let div, conv = list_split (List.length div) all_tms in + let varno = List.length var_names in + let p = {orig_freshno=varno; freshno=1+varno; 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 @@ -347,14 +443,22 @@ let magic6 div conv cmds = 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 all_tms, var_names = parse (div @ conv) in + let div, conv = list_split (List.length div) all_tms in + let varno = List.length var_names in + let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]} in + (* activate bombs *) let p = try let subst = Util.index_of "BOMB" var_names, L B in - let p = subst_in_problem subst p in p + subst_in_problem subst p + with Not_found -> p in + (* activate pacmans *) + let p = try + let subst = Util.index_of "PACMAN" var_names, P in + let p = subst_in_problem subst p in + (print_endline ("after subst in problem " ^ string_of_problem p); p) with Not_found -> p in + (* initial sanity check *) let p = sanity p in let p = List.fold_left (|>) p cmds in let rec f p cmds = @@ -368,37 +472,38 @@ let interactive div conv cmds = 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 = "forget" then forget (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 + else failwith "Wrong input." + with Failure s -> print_endline s; (fun x -> x) in let str, cmd = read_cmd () in - let cmds = str::cmds in + let cmds = (" " ^ str ^ ";")::cmds in try let p = cmd p in f p cmds with - | Done -> List.iter print_endline (List.rev cmds) + | Done -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds) in f p [] ;; let _ = magic6 - "x x" + ["x x"] [ "_. BOMB" ] [ ignore 1 1; explode ] ;; let _ = magic6 - "x y BOMB b" + ["x y BOMB b"] [ "x BOMB y c" ] - [ perm 1 3; step 1 ; ignore 8 2; explode; ];; + [ perm 1 3; step 8 ; explode; ];; let _ = magic6 - "x BOMB a1 c" + ["x BOMB a1 c"] [ "x y BOMB d"; "x BOMB a2 c" ] - [ perm 1 3 ; step 1 ; step 12; ignore 13 1; explode; ] + [ perm 1 3 ; step 10 ; step 13; explode; ] ;; let _ = magic6 - "x (x x)" + ["x (x x)"] [ "x x" ; "x x x" ] [ apply 1 1; step 1; @@ -407,44 +512,56 @@ let _ = magic6 ];; let _ = magic6 - "x (_.BOMB)" + ["x (_.BOMB)"] [ "x (_._. BOMB)" ] [ apply 1 2; ] ;; let _ = magic6 - "x (_.y)" + ["x (_.y)"] [ "y (_. x)" ] [ apply 1 1; ignore 1 1; explode; ] ;; let _ = magic6 - "y (x a1 BOMB c) (x BOMB b1 d)" + ["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; ] + "y (x a1 BOMB c) (x BOMB b2 d)";] [ + perm 2 3; + step 12; + perm 17 2; + step 19; + step 18; + ignore 22 1; + ignore 21 1; + ignore 24 1; + ignore 25 1; + step 1; + step 32; + explode; + ] ;; let _ = magic6 - "z (y x)" + ["z (y x)"] [ "z (y (x.x))"; "y (_. BOMB)" ] - [ apply 2 1; step 3; explode' 8; ] + [ apply 2 1; step 3; explode; ] ;; let _ = magic6 - "y x" + ["y x"] [ "y (x.x)"; "x (_. BOMB)" ] [ apply 1 1; ignore 2 1; step 1; explode; ] ;; let _ = magic6 - "z (y x)" + ["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 a)"] [ "y (x b)"; "x BOMB" ] [ id 2; step 1; @@ -452,23 +569,47 @@ let _ = magic6 ];; magic6 - "y (x a)" [ "y (x b)"; "x BOMB"; "y a" ] + ["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; + ignore 9 1; + step 10; explode; + ];; +(* "y (a c)" +[ "y (b c)"; "y (x a)"; "y (x b)"; "x BOMB" ] *) + +magic6 +["x a (x (a.y BOMB))"] +[ "x b"; "x (y c)"; "x (y d)" ] +[apply 1 1; +apply 2 1; +explode;] +(* [ +step 1; +step 3; +explode' 10; +(* ma si puo' fare anche senza forget *) *) +(* ] *) +;; + +(* dipendente dalla codifica? no, ma si risolve solo con id *) +magic6 + ["y a"] ["y b"; "x (y (_.BOMB))"] +[ +apply 1 1; +apply 2 1; +explode; ];; + (* [id 1; explode];; *) -interactive - "y (x a)" -[ "y (x b)"; "x BOMB"; "y a" ] [];; +magic6 + ["PACMAN (x x x)"] ["PACMAN (x x)"] + [ + ignore 2 2; + explode; + ];; +print_hline(); print_endline "ALL DONE. " diff --git a/ocaml/andrea7.ml b/ocaml/andrea7.ml new file mode 100644 index 0000000..4a27c79 --- /dev/null +++ b/ocaml/andrea7.ml @@ -0,0 +1,751 @@ +let (++) f g x = f (g x);; + +let print_hline = Console.print_hline;; + +type var = int;; +type t = + | V of var + | A of t * t + | L of t + | B (* bottom *) + | P (* pacman *) + | Stuck of var * int + (* | Ptr of int *) +;; + +let rec consts = (* const_apps, const_lambda *) + let rec aux1 = function + | A(t, _) -> 1 + aux1 t + | _ -> 0 in + let rec aux2 = function + | L t -> 1 + aux2 t + | _ -> 0 in + function + | A(t1, t2) as t -> + let a1, b1 = consts t1 in + let a2, b2 = consts t2 in + max (aux1 t) (max a1 a2), max b1 b2 + | L t' as t -> + let a, b = consts t' in + a, max (aux2 t) b + | _ -> 0, 0 +;; + + +type problem = { + orig_freshno: int + ; freshno : int + ; div : t + ; conv : t list + ; matches : (var (* variable originating this match *) * ((int (* index of the term to discriminate *) * var option (* continuation *))) list) list + ; sigma : (var * t) list (* substitutions *) + ; stepped : var list + ; arities : (var * int) list + ; k_app : int + ; k_lam : int +} + +let dummy_p = {orig_freshno=0; freshno=0; div=B; conv=[]; matches=[]; sigma=[]; stepped=[]; arities=[]; k_app=0;k_lam=0};; + +let append_conv p t = let len = List.length p.conv in let p = {p with conv=t::p.conv} in p, len;; +let get_conv p n = List.nth p.conv (List.length p.conv - 1 - n);; +let index_of_conv t conv = List.length conv - 1 - (Util.index_of t conv);; + +let eq_conv = (=);; +let eq_conv_indices p i j = eq_conv (get_conv p i) (get_conv p j);; +let all_terms p = p.div :: p.conv;; + +exception Done of (var * t) list (* substitution *);; +exception Fail of int * string;; + +let string_of_t p = + let bound_vars = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"; "x3"; "x4"; "x5"] in + let rec string_of_term_w_pars level = function + | V v -> if v >= level then "`" ^ string_of_int (v-level) else List.nth bound_vars (level - v-1) + | A _ + | L _ as t -> "(" ^ string_of_term_no_pars_lam level t ^ ")" + | B -> "BOT" + | P -> "PAC" + | Stuck _ as t -> "(" ^ string_of_term_no_pars_app level t ^ ")" + (* | Ptr _ as t-> "(" ^ string_of_term_no_pars_app level t ^ ")" *) + (* "&" ^ string_of_int n *) + and string_of_term_no_pars_app level = function + | A(t1,t2) -> (string_of_term_no_pars_app level t1) ^ " " ^ (string_of_term_w_pars level t2) + | Stuck(v,n) -> ":" ^ string_of_term_no_pars_app level (V v) ^ " " ^ (string_of_term_w_pars level (get_conv p n)) + (* | Ptr n -> string_of_term_no_pars_app level (get_conv p n) *) + (* | Ptr n -> "&" ^ string_of_int n *) + | _ as t -> string_of_term_w_pars level t + and string_of_term_no_pars_lam level = function + | L t -> "λ" ^ string_of_term_w_pars (level+1) (V 0) ^ ". " ^ (string_of_term_no_pars_lam (level+1) t) + | _ as t -> string_of_term_no_pars level t + and string_of_term_no_pars level = function + | L _ as t -> string_of_term_no_pars_lam level t + | _ as t -> string_of_term_no_pars_app level t + in string_of_term_no_pars 0 +;; + +let string_of_problem p = + let lines = [ + "[arities] " ^ String.concat " " (List.map (fun (v,n) -> "`" ^ string_of_int v ^ "=" ^ string_of_int n) p.arities); + "[stepped]" ^ String.concat " " (List.map string_of_int p.stepped); + "[DV] " ^ (string_of_t p p.div); + "[CV] " ^ String.concat "\n " (List.map (string_of_t p) p.conv); + (* "" ; *) + ] @ Util.concat_map (fun (v, lst) -> ("[<>] of "^(string_of_t p (V v))) :: List.map (fun (n,c) -> " " ^ string_of_t p (get_conv p n) + ^ (match c with None -> "" | Some v -> " -> " ^ string_of_t p (V v)) + ) lst) p.matches @ [""] in + String.concat "\n" lines +;; + +let problem_fail p reason = + print_endline "!!!!!!!!!!!!!!! FAIL !!!!!!!!!!!!!!!"; + print_endline (string_of_problem p); + raise (Fail (-1, reason)) +;; + +let freshvar ({freshno} as p) = + {p with freshno=freshno+1}, freshno+1 +;; + +let add_to_match p id t = + let p, entry = + try + p, index_of_conv t p.conv + with + | Not_found -> append_conv p t in + let entry' = entry, None in + let matches = + List.map (fun (id',lst as x) -> if id <> id' then x else (id, entry'::lst)) p.matches + in + {p with matches}, entry +;; + +let var_occurs_in p v = + let rec aux level = function + | V v' -> v + level = v' + | Stuck(v',n) -> assert (v <> v'); aux level (get_conv p n) + | A(t1,t2) -> (aux level t1) || (aux level t2) + | L t -> aux (level+1) t + | B -> false + | P -> false + (* | Ptr n -> aux level (get_conv p n) *) + + in aux 0 +;; + +let rec is_inert p = + function + | A(t,_) -> is_inert p t + (* | Ptr n -> is_inert p (get_conv p n) *) + | V _ | Stuck _ -> true + | L _ | B | P -> false +;; + +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) + | B -> p, B + | P -> p, P + (* | Ptr _ as t -> p, t *) + | Stuck(v,_) as t -> + assert (v <> level + fst sub); (* can't instantiate v twice after a step *) + (* FIXME!!!! URGENT!!! *) + p, t +and mk_app p t1 t2 = let t1 = if t1 = P then L P else t1 in match t1 with + | L t1 -> subst 0 true (0, t2) p t1 + | V v when List.mem v p.stepped -> + let p, n = add_to_match p v t2 in + p, Stuck(v, n) + | 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 = + let rec aux n' = + function + | V m -> V (if m >= n' then m + n else m) + | L t -> L (aux (n'+1) t) + | A (t1, t2) -> A (aux n' t1, aux n' t2) + | B -> B + | P -> P + | Stuck(m,ptr) -> assert (m >= n'); Stuck(m + n, ptr) + (* | Ptr _ as t -> t *) + in aux 0 +;; + +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, tms = aux p tms in + let p, t = subst sub p t in + p, t :: tms + in aux +;; + +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)); *) +(* BUG QUI FIXME!!!! *) + let rec mix l1 l2 = match l1, l2 with + | [], l2 -> l2 + | x::xs, _::ys -> x:: (mix xs ys) + | _ -> assert false in + let p, conv = subst_many sub p p.conv in + let p, div = subst sub p p.div in + let conv = List.rev (mix (List.rev conv) (List.rev p.conv)) in + let p = {p with div; conv} in + (* print_endline ("after sub: \n" ^ string_of_problem p); *) + {p with sigma=sub::p.sigma} +;; + +let problem_done p = + let all_separated = List.for_all (fun (_, lst) -> List.for_all (fun (n,_) -> is_var (get_conv p n)) lst) p.matches in + all_separated && p.div = B +;; + +let free_vars p t = + let rec aux level = function + | V v -> if v >= level then [v] else [] + | A(t1,t2) -> (aux level t1) @ (aux level t2) + | L t -> aux (level+1) t + | B | P + | Stuck _ -> [] + (* | Ptr n -> aux 0 (get_conv p n) *) + in Util.sort_uniq (aux 0 t) +;; + +let visible_vars p t = + let rec aux = function + | V v -> [v] + | A(t1,t2) -> (aux t1) @ (aux t2) + | B | P + | Stuck _ | L _ -> [] + (* | Ptr n -> aux (get_conv p n) *) + in Util.sort_uniq (aux t) +;; + +(* TODO FIXME *) +let apply_substs p t = t;; + +let unblock var index cont p = + let rec aux p = function + | Stuck(v',n') as t -> p, (if var = v' && index = n' then apply_substs p (V cont) else t) + | A (t1, t2) -> + let p, t1 = aux p t1 in + let p, t2 = aux p t2 in + mk_app p t1 t2 + | _ as t -> p, t in + let p, div = aux p p.div in + let _, conv = List.fold_right (fun c (p, conv) -> let p, c = aux p c in p, c::conv) p.conv (p,[]) in + {p with div; conv} +;; + +let rec unblock_all p = + let aux (orig, m) (matches, news, p) = + let nn = List.filter (fun (n,c) -> is_var (get_conv p n) && c = None) m in + let p, conts = List.fold_left (fun (p,conts) (n,_) -> + match Util.find_opt (function (n', c) when eq_conv_indices p n' n -> c | _ -> None) m + with Some c -> p, (n, c)::conts | None -> + (* c is the new continuation *) + let p, c = freshvar p in + let arity = c, List.assoc orig p.arities - 1 in + print_endline ("``" ^ string_of_int orig); + assert ((snd arity) > -1 ); + let p = {p with arities=arity::p.arities} in + p, (n, c)::conts + ) (p, []) nn in + let m = List.map (fun (n,c) -> n, try + Some (List.assoc n conts) + with + | Not_found -> c) m in + (orig, m) :: matches, (List.map (fun x -> orig, x) conts) @ news, p + in + let matches, news, p = List.fold_right aux p.matches ([],[], p) in + (* FIXPOINT *) + if news <> [] then + let f = List.fold_left (fun f (a,(b,c)) -> f ++ (unblock a b c)) (fun p -> p) news in + unblock_all (f {p with matches}) else p +;; + +let rec simple_explode p = + match p.div with + | V var -> + let subst = var, B in + sanity (subst_in_problem subst p) + | _ -> p + +and sanity p = + (* Sanity checks: *) + if (function | P | L _ -> true | _ -> false) p.div then problem_fail p "p.div converged"; + if List.mem B p.conv then problem_fail p "p.conv diverged"; + if not (List.for_all (fun (_, lst) -> List.for_all (fun (n,_) -> is_inert p (get_conv p n)) lst) p.matches) + then problem_fail p "Unsolvable discrimination"; + + let p = unblock_all p in + print_endline (string_of_problem p); (* non cancellare *) + let p = if problem_done p then raise (Done p.sigma) else p in + let p = if is_var p.div then simple_explode p else p in + p +;; + +let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);; + +let rec hd_args t = match t with + | V v -> v, [] + | A(t1,t2) -> let a, b = hd_args t1 in a, b @ [t2] + | _ -> -666, [] +;; + +let max_arity_of_var v = + let rec aux level = + function + | V _ -> 0 + | A _ as t -> print_string (string_of_t dummy_p t); let hd, args = hd_args t in + let acc = if hd = level + v then List.length args else 0 in + List.fold_right (max ++ (aux level)) args acc + | L t -> aux (level + 1) t + | Stuck(v,n) -> 0 + (* | Ptr n -> assert false *) + | P | B -> 0 + in aux 0 +;; + +let ignore var n p = + print_cmd "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 p, fresh = freshvar p in + let subst = var, aux n (V fresh) in + sanity (subst_in_problem subst p) +;; + + + +let eat var p = + print_cmd "EAT" ("var " ^ string_of_t p (V var)); + let rec is_hd v' = function + | A (t,_) -> is_hd v' t + | V v -> v' = v + | _ -> false in + let rec app_length = function + | A (t,_) -> 1 + app_length t + | _ -> 0 in + let rec find_app_no = function + | V _ | L _ | P | B -> 0 + | A (t1,t2) as t -> + max (max (find_app_no t1) (find_app_no t2)) + (if is_hd var t1 then app_length t else 0) + | Stuck _ -> 0 + (* | Ptr n -> find_app_no (get_conv p n) *) + in let n = List.fold_right (max ++ find_app_no) (all_terms p) 0 in + let rec aux m t = + if m = 0 + then lift n t + else L (aux (m-1) t) in + let p, fresh = freshvar p in + let subst = var, aux n (V fresh) in + sanity (subst_in_problem subst p) +;; + +(* let explode p = + let fv1 = visible_vars p p.div in + let fv2 = List.concat (List.map (visible_vars p) p.conv) in + let fv = List.filter (fun x -> not (List.mem x fv2)) fv1 in + let fv = List.filter ((<) p.orig_freshno) fv in + match fv with + | var::_ -> + print_cmd "EXPLODE" ("on " ^ string_of_t p (V var)); + let subst = var, B in + sanity (subst_in_problem subst p) + | _ -> raise (Fail (-1,"premature explosion")) +;; *) + +(* let step var p = + print_cmd "STEP" ("on " ^ string_of_t p (V var)); + let matches = (var,[])::p.matches in + let p = {p with matches;stepped=var::p.stepped} in + let subst = var, V var in + sanity (subst_in_problem subst p) +;; *) + +let choose n p = + print_cmd "CHOOSE" ("#" ^ string_of_int n); + let rec aux n t = match t with + | V _ -> 0, t + | A(t1,_) -> let n', t' = aux n t1 in if n = n' then n', t' else n'+1, t + | _ -> assert false + in let n', div = aux n p.div in + if n' <> n then problem_fail p "wrong choose"; + let p = {p with div} in + sanity p +;; + +let apply var appk p = + print_cmd "APPLY" + (string_of_t p (V var) ^ " applies no." ^ string_of_int appk ^ " fresh variables"); + 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 find_arities_after_app p = + let rec aux level n = function + | L t -> assert (n > 0); max_arity_of_var level t :: aux (level+1) (n-1) t + | _ -> Array.to_list (Array.make n 0) + in aux 0 +;; +let find_all_first_args_of v = + let rec aux level = function + | L t -> aux (level+1) t + | V _ -> [] + | A(V v', t2) -> (if v + level = v' then [t2] else []) @ aux level t2 + | A(t1,t2) -> aux level t1 @ aux level t2 + | _ -> [] + in aux 0 +;; + +let step' var p = + let appk = p.k_lam + p.k_app + 1 in + print_cmd "STEP'" ("on " ^ string_of_t p (V var) ^ " and applies no." ^ string_of_int appk ^ " fresh variables"); + let p, vars = (* +1 below because of lifting *) + Array.fold_left (fun (p,vars) _ -> let p, v = freshvar p in p, (v+1)::vars) + (p, []) (Array.make appk ()) in + let p, t = mk_apps p (V 0) (List.map (fun x -> V x) vars) in + + let first_args = Util.sort_uniq (List.fold_right ((@) ++ (find_all_first_args_of var)) (all_terms p) []) in + let map = List.fold_left (fun acc t -> let acc' = find_arities_after_app p appk t in List.map (fun (x,y) -> max x y) (List.combine acc acc')) (Array.to_list (Array.make appk 0)) first_args in + let arities = List.combine (List.map ((+) (-1)) vars) map in + + (* let p, var' = freshvar p in *) + let p, var' = p, var in + let matches = (var', []) :: p.matches in + let p = {p with matches; stepped=var'::p.stepped; arities=arities@p.arities} 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 = + if n = 1 then p else ( + print_cmd "PERM" ("on " ^ string_of_t p (V var) ^ " (of:" ^ string_of_int n ^ ")"); + (* let p, v = freshvar p in *) + let p, v = p, var 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 v)) in + let subst = var, t in + (* let p = {p with arities=(v, List.assoc var p.arities)::p.arities} in *) + sanity (subst_in_problem subst p) +) ;; + +let free_vars_of_p p = + Util.sort_uniq (Util.concat_map (free_vars p) (all_terms p));; + +let rec applied_vars p = function +| B | P -> [] +| L _ -> [] (* ??? *) +| V _ -> [] +| A(V v,t2) -> v :: applied_vars p t2 +| A(t1,t2) -> applied_vars p t1 @ applied_vars p t2 +(* | Ptr n -> applied_vars p (get_conv p n) *) +| Stuck _ -> [] (* ??? *) +;; + +let applied_vars_of_p p = + Util.sort_uniq (Util.concat_map (applied_vars p) (all_terms p));; + +let rec auto p = + let aux f var = + try + auto (f var); () + with + | Done _ as d -> raise d + | Fail(_, s) -> print_endline ("<<< Backtracking because: " ^ s) in + print_endline ">>> auto called"; + (* Compute useful free variables *) + let fv = applied_vars_of_p p in + let fv = List.filter (fun v -> not (List.mem v p.stepped)) fv in + List.iter (fun v -> print_string ("@`" ^ string_of_int v)) fv; + let fv0 = List.filter (fun v -> List.assoc v p.arities > 0) fv in (* remove variable with arity left 0, cannot step there *) + if fv0 = [] then (print_endline "warning! empty step fv0"; List.iter (fun v -> print_string ("@`" ^ string_of_int v)) fv); + let permute_and_step p v = + let step'' problem prm var = + let problem = perm var prm problem in + (* let _ = read_line () in *) + let problem = step' var problem in + problem in + let arity = List.assoc v p.arities in + let _, perms = Array.fold_left (fun (arity, acc) () -> let a = arity + 1 in a, a::acc) (1,[1]) (Array.make (arity-1) ()) in + List.iter (fun perm -> aux (step'' p perm) v) perms + in + List.iter (permute_and_step p) fv0; + List.iter (aux (fun v -> eat v p)) fv; + (* mancano: applicazioni e choose; ??? *) +;; + +let parse strs = + 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 varno = List.length var_names in + let k_app, k_lam = List.fold_left (fun (a, b) t -> let a', b' = consts t in max a a', max b b') (0,0) all_tms in + let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]; stepped=[];k_app;k_lam;arities=[]} in + let fv = Util.sort_uniq (Util.concat_map (free_vars p) all_tms) in + let arities = List.map (fun var -> var, k_app) fv in + let p = {p with arities} 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 auto div conv = + print_hline (); + let all_tms, var_names = parse (div :: conv) in + let div, conv = List.hd all_tms, List.tl all_tms in + let varno = List.length var_names in + let k_app, k_lam = List.fold_left (fun (a, b) t -> let a', b' = consts t in max a a', max b b') (0,0) all_tms in + let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]; stepped=[];k_app;k_lam;arities=[]} in + let fv = Util.sort_uniq (Util.concat_map (free_vars p) all_tms) in + let max_arity_of_var_in_p var p = + 1 + List.fold_right (max ++ (max_arity_of_var var)) (all_terms p) 0 in + let arities = List.map (fun var -> var, max_arity_of_var_in_p var p) fv in + let p = {p with arities} 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 + auto p; + failwith "auto failed." + with + | Done _ -> print_endline "<<< auto ok >>>"; (* TODO: print and verify substitution *) +;; + +(* let interactive div conv cmds = + print_hline (); + let all_tms, var_names = parse (div @ conv) in + let div, conv = list_split (List.length div) all_tms in + let varno = List.length var_names in + let p = {orig_freshno=varno; freshno=1+varno; div; conv; matches=[]; sigma=[]} in + (* activate bombs *) + let p = try + let subst = Util.index_of "BOMB" var_names, L B in + subst_in_problem subst p + with Not_found -> p in + (* activate pacmans *) + let p = try + let subst = Util.index_of "PACMAN" var_names, P in + let p = subst_in_problem subst p in + (print_endline ("after subst in problem " ^ string_of_problem p); p) + with Not_found -> p in + (* initial sanity check *) + 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 = "forget" then forget (nth spl 1) (nth spl 2) *) + else if uno = "id" then id (nth spl 1) + else failwith "Wrong input." + with Failure s -> print_endline s; (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 -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds) + in f p [] +;; *) + +let _ = auto + "x x" + [ "_. BOMB" ] + (* [ eat 1 ] *) +;; + + +let _ = auto + "x y BOMB b" + [ "x BOMB y c" ] + (* [ perm 1 3; step' 8 ; eat 4; eat 5; eat 15; ] *) +;; + + +let _ = auto + "x BOMB a1 c" + [ "x y BOMB d"; "x BOMB a2 c" ] + (* [ perm 1 3 ; step' 10 ; eat 4; eat 6; step' 17; eat 3; eat 7; eat 27; ] *) +;; + + +let _ = auto + "x (x x)" + [ "x x" ; "x x x" ] + (* [ + step' 1; + eat 6; eat 9; eat 13; +]*) +;; + + +(* let _ = auto + "x (_.BOMB)" + [ "x (_._. BOMB)" ] + (* [ apply 1 2; ] *) +;; *) + + +let _ = auto + "x (_.y)" + [ "y (_. x)" ] + (* [ apply 1 1; ignore 1 1; explode; ] *) +;; + + +let _ = auto + "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 12; + perm 17 2; + step 19; + step 18; + ignore 22 1; + ignore 21 1; + ignore 24 1; + ignore 25 1; + step 1; + step 32; + explode; + ] *) +;; + +(* +let _ = magic6 + ["z (y x)"] + [ "z (y (x.x))"; "y (_. BOMB)" ] + [ apply 2 1; step 3; explode; ] +;; + +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; + ignore 9 1; + step 10; + explode; + ];; +(* "y (a c)" +[ "y (b c)"; "y (x a)"; "y (x b)"; "x BOMB" ] *) + +magic6 +["x a (x (a.y BOMB))"] +[ "x b"; "x (y c)"; "x (y d)" ] +[apply 1 1; +apply 2 1; +explode;] +(* [ +step 1; +step 3; +explode' 10; +(* ma si puo' fare anche senza forget *) *) +(* ] *) +;; + +(* dipendente dalla codifica? no, ma si risolve solo con id *) +magic6 + ["y a"] ["y b"; "x (y (_.BOMB))"] +[ +apply 1 1; +apply 2 1; +explode; +];; + (* [id 1; explode];; *) + +magic6 + ["PACMAN (x x x)"] ["PACMAN (x x)"] + [ + ignore 2 2; + explode; + ];; *) + +print_hline(); +print_endline "ALL DONE. " diff --git a/ocaml/lambda4.ml b/ocaml/lambda4.ml index dbd7396..6b59ed9 100644 --- a/ocaml/lambda4.ml +++ b/ocaml/lambda4.ml @@ -5,16 +5,24 @@ open Num let bomb = ref(`Var ~-1);; +type var = int;; + type problem = { freshno: int ; div: i_var option (* None = bomb *) ; conv: i_n_var list (* the inerts that must converge *) ; ps: i_n_var list (* the n-th inert must become n *) - ; sigma: (int * nf) list (* the computed substitution *) + ; sigma: (var * nf) list (* the computed substitution *) ; deltas: (int * nf) list ref list (* collection of all branches *) - ; steps: int (* how many steps the algorithm made until now *) + (* ; steps: int (* the bound on the number of steps *) *) + ; arities: int list + ; special_k: int } +let string_of_nf {freshno} t = + let l = Array.to_list (Array.init (freshno + 1) string_of_var) in + print ~l (t :> nf) +;; (* let heads = Util.sort_uniq (List.map hd_of_i_var p.ps) in for all head @@ -22,6 +30,7 @@ for all head (* let ($) f x = f x;; *) + let subterms tms freshno = let apply_var = let no = ref freshno in @@ -52,7 +61,7 @@ let all_terms p = ;; let problem_measure p = - let l = Array.to_list (Array.init (p.freshno + 1) string_of_var) in + (* let l = Array.to_list (Array.init (p.freshno + 1) string_of_var) in *) let open Listx in (* aux |t1;t2| e' numero di step per portare la diff in testa INVARIANTE: t1 t2 @@ -78,7 +87,7 @@ let problem_measure p = (* no. di step da fare per separare t1 e t2 *) in let diff t1 t2 = ( let res = if eta_eq t1 t2 then 0 else aux t1 t2 in - if res <> 0 then prerr_endline ("diff (" ^ print ~l t1 ^ ") (" ^ print ~l t2 ^ ") = " ^ string_of_int res); + (* if res <> 0 then prerr_endline ("diff (" ^ print ~l t1 ^ ") (" ^ print ~l t2 ^ ") = " ^ string_of_int res); *) res ) (* aux calcola la somma delle differenze tra i termini in una lista (quadratico) *) @@ -93,13 +102,223 @@ let problem_measure p = in a + b ;; -let print_problem label ({freshno; div; conv; ps; deltas; steps} as p) = +(* AC MEASURE *) +module ACMeasure = struct +type var = int;; + +type state = { + freshno : int; + arities : int list; + p : problem; +} + +let string_of_state s = + "STATE\n - arities: " ^ + String.concat " " (List.mapi (fun v n -> "`"^string_of_var v ^ "=" ^ string_of_int n) s.p.arities) +;; + +let rec get_var_of_match bs p = + let rec aux = function + | (v,`Lam(_,`Match(_,_,bs',_)))::sigma -> if bs = bs' then v else aux sigma + | _::sigma -> aux sigma + | [] -> assert false + in aux p.sigma +;; + +let mk_freshvar s = + let freshno = s.freshno + 1 in + {s with freshno}, freshno +;; + +let rec mk_apps vmap (h : nf) (args : var list) = + let aux l = Listx.from_list (List.map (fun x -> `Var x) l) in + match h,args with + | _, [] -> vmap, h + | `I(n,args'), _ -> vmap, `I(n, Listx.append (aux args) args') + | `Var n, _ -> vmap, `I(n, aux args) + | `Lam(_,nf), a::args -> mk_apps (a::vmap) (lift ~-1 nf) args + | `Match(t,lift,bs,args'), _ -> vmap, `Match(t,lift,bs,List.append args' (Listx.to_list (aux args))) + | _ -> assert false +;; + +let mk_freshvars s n = Array.fold_right (fun () (s,acc) -> let s, v = mk_freshvar s in s, v::acc ) (Array.make n ()) (s, []) +;; + +let get_arity_of_var p v t = + (* prerr_endline (string_of_nf p t); *) + let rec aux level = function + | `Var _ | `N _-> 0 + | `I(v', tms) as t -> + max + (if v + level = v' then ( + (* prerr_endline("found applied " ^ string_of_var v ^" in "^print (lift (-level) t)); *) + Listx.length tms) else 0) + (aux_listx level tms) + | `Lam(_,t) -> aux (level + 1) t + | `Match(t, liftno, bs, args) -> max (aux level (t :> nf)) (aux_list level args) + and aux_listx level listx = Listx.fold_left (fun x t -> max x (aux level t)) 0 listx + and aux_list level lst = List.fold_left (fun x t -> max x (aux level t)) 0 lst + in aux 0 t +;; + +(* let mk_apps t args = List.fold_left mk_app t args;; *) + +let first_arg = function + | Listx.Nil x + | Listx.Cons(x,_) -> x +;; + +let find_first_args var = + let rec aux level : nf -> nf list = function + | `Var _ | `N _ -> [] + | `I(v, args) -> (if var + level = v then [first_arg args] else []) @ (Util.concat_map (aux level) (Listx.to_list args)) + | `Lam(_,t) -> aux (level+1) t + | `Match(t, liftno, bs, args) -> aux level (t :> nf) @ (Util.concat_map (aux level) (args)) + in aux 0 +;; + +let remove_lambdas k t = + let rec aux = function + | `Lam(_,t) -> aux t + | _ as t -> t + in lift (-k) (aux t) +;; + +let get_arity_of_continuation p v = + if !bomb = `Var v then 0 else ( + let bs = List.find (fun bs -> List.exists (fun (_,t) -> t = `Var v) !bs) p.deltas in + let orig = get_var_of_match bs p in + List.nth p.arities orig + ) +;; + +let fix_arities p v freshvars = + let all_terms = (all_terms p :> nf list) in + let args = Util.concat_map (find_first_args v) all_terms in + let k = List.length freshvars in + let args = List.map (remove_lambdas k) args in + prerr_endline ("delifted lambdas in which to look for "^ string_of_var v); + (* List.iter (fun t -> prerr_endline(strilogng_of_nf p t)) args; *) + (* assert (List.length args > 0); *) + List.iter (fun v -> prerr_endline ("var to fix: fresh " ^ string_of_var v)) freshvars; + let find_arities_args v = let i = List.fold_left (fun x t -> max x (get_arity_of_var p v t)) 0 args in prerr_endline ("found arity in args of " ^ string_of_var (List.nth (List.rev freshvars) (v+1)) ^ ": " ^ string_of_int i); i in + (* let find_arities_all v = List.fold_left (fun x t -> max x (get_arity_of_var p v t)) 0 all_terms in *) + let arities = List.mapi (fun var () -> + if var < List.length p.arities + then List.nth p.arities var + else if List.mem var freshvars + then 1 + find_arities_args (Util.index_of var (List.rev freshvars) - 1) + (* else find_arities_all var *) + else (get_arity_of_continuation p var) - 1 + ) (Array.to_list (Array.make (p.freshno+1) ())) in + assert (List.length arities = (p.freshno + 1)); + (* prerr_endline ("arities added : " ^ string_of_int (List.length freshvars)); *) + (* List.iter (fun (v,n) -> prerr_endline(string_of_int v ^ "=" ^ string_of_int n)) arities; *) + {p with arities} +;; + +let measure = + let rec aux (s:state) vmap = + let p = s.p in + let realvar vmap v = + (* prerr_endline ("waant " ^ string_of_int v ^ "; we have "^ string_of_int (List.length vmap)); *) + if v < 0 then List.nth vmap (-1-v) else v in + function + | `Var _ | `N _-> 0 + | `I(v, tms) -> assert (List.length s.arities = (s.freshno + 1)); 1 + + let v = realvar vmap v in + (* prerr_endline ("lookup for arity of " ^ string_of_int v ^ "with freshno =" ^ string_of_int s.freshno ^ " and length = " ^ string_of_int (List.length s.arities)); *) + let arity = List.nth s.arities v in + 1 + if arity = 0 then 0 else ( + let first, rest = (match tms with + | Listx.Nil x -> x, [] + | Listx.Cons(a,b) -> a, Listx.to_list b) in + ( + let s, vars = mk_freshvars s (1+s.p.special_k) in + let vmap, t = mk_apps vmap first (vars) in + let arities = List.mapi (fun v () -> + if v < List.length s.arities + then List.nth s.arities v + else get_arity_of_var p (realvar vmap v) t + ) (Array.to_list (Array.make (s.freshno + 1) ())) in + (* let arities = (List.map (fun v -> v, get_arity_of_var p (realvar vmap' v) t) vars) in *) + (* let arities = arities @ s.arities in *) + let s = {s with arities} in + aux s vmap t + ) + ( + let s, fresh = mk_freshvar s in + let arities = s.arities @ [arity - 1] in + let s = {s with arities} in + if rest = [] then aux s vmap (`Var fresh) else + aux s vmap (`I (fresh, Listx.from_list rest)) + ) + ) + | `Match(t, _, bs, rest) -> + let tmp = aux s vmap (t :> nf) in + let s, fresh = mk_freshvar s in + let arity = List.nth s.arities (get_var_of_match bs s.p) in + let arities = s.arities @ [arity - 1] in + let s = {s with arities} in + tmp + if rest = [] then aux s vmap (`Var(fresh)) else + aux s vmap (`I(fresh, Listx.from_list rest)) + | `Lam _ -> assert false + in fun s -> aux s [] +;; + + +(* let measure p = + let rec m = function + | `N _ | `Var _ -> 0 + | `I(_,args) -> + let args = Listx.to_list args in + List.fold_left (fun acc t -> acc + m t) (1 + Listx.length args) args + | `Lam(_,t) -> m t + | `Match(t, lft, bs, rest) -> + (* let var = get_var_of_match bs p in *) + let args = rest in m (t :> nf) + List.fold_left (fun acc t -> acc + m t) (aux args) args + +and aux = function + | [] -> 0 + | x::xs -> m x + if aux xs = 0 then 0 else 1 + aux xs +in m +;;*) + +let measure_many s tms = List.fold_left (fun x t -> x + (measure s t)) 0 tms;; + +let map_max f l = List.fold_left (fun x t -> max x (f t)) 0 l;; + +let measure_of_problem p = + let tms = (all_terms p :> nf list) in + let freshno = p.freshno in + let arities = p.arities in + let s = {arities; freshno; p} in + prerr_endline (string_of_state s); + let l = Array.to_list (Array.init (freshno + 1) string_of_var) in + List.iter (fun t -> prerr_endline (string_of_int (measure s t) ^ " ::" ^ print ~l t)) tms; + let m = measure_many s tms in + (* prerr_endline (string_of_int m); *) + m +;; +end;; + +let measure_of_problem = ACMeasure.measure_of_problem;; +let problem_measure = measure_of_problem;; +(* AC MEASURE *) + +let print_problem label ({freshno; div; conv; ps; deltas} as p) = + (* assert (p.steps > List.length p.sigma); *) + let measure = try + problem_measure p + with + | _ -> -1 in Console.print_hline (); prerr_endline ("\n||||| Displaying problem: " ^ label ^ " |||||"); let nl = "\n| " in let deltas = String.concat nl (List.map (fun r -> String.concat " <> " (List.map (fun (i,_) -> string_of_int i) !r)) deltas) in let l = Array.to_list (Array.init (freshno + 1) string_of_var) in - nl ^ string_of_int steps ^ " steps left; measure="^string_of_int(problem_measure p)^" freshno = " ^ string_of_int freshno + nl ^ + (* (string_of_int (steps - List.length p.sigma)) ^ " steps left;" ^ *) + "measure="^string_of_int measure ^" freshno = " ^ string_of_int freshno ^ nl ^ "\b> DISCRIMINATING SETS (deltas)" ^ nl ^ deltas ^ (if deltas = "" then "" else nl) ^ "\b> DIVERGENT" ^ nl @@ -262,7 +481,7 @@ prerr_endline ("# INST: " ^ string_of_var x ^ " := " ^ print ~l inst)); ); let p = {p with sigma = sigma@[x,inst]} in let p = super_simplify p in - prerr_endline (print_problem "instantiate" p); + print_endline (print_problem "instantiate" p); p ;; @@ -441,13 +660,13 @@ prerr_endline ("# INST_IN_EAT: " ^ string_of_var x ^ " := " ^ print ~l inst)); let p, bomb' = make_fresh_var p in (if !bomb <> `Var (-1) then failwithProblem p - ("Bomb was duplicated! It was " ^ string_of_nf !bomb ^ - ", tried to change it to " ^ string_of_nf bomb')); + ("Bomb was duplicated! It was " ^ string_of_nf p !bomb ^ + ", tried to change it to " ^ string_of_nf p bomb')); bomb := bomb'; - prerr_endline ("Just created bomb var: " ^ string_of_nf !bomb); + prerr_endline ("Just created bomb var: " ^ string_of_nf p !bomb); let x = hd_of_i_var div in let inst = make_lams !bomb n in - prerr_endline ("# INST (div): " ^ string_of_var x ^ " := " ^ string_of_nf inst); + prerr_endline ("# INST (div): " ^ string_of_var x ^ " := " ^ string_of_nf p inst); let p = {p with div=None} in (* subst_in_problem (hd_of_i_var div) inst p in *) {p with sigma=p.sigma@[x,inst]} in @@ -480,7 +699,7 @@ List.iter (fun l -> prerr_endline (String.concat " " (List.map string_of_var l)) let old_conv = p.conv in let p = { p with ps; conv } in if l <> [] || old_conv <> conv - then prerr_endline (print_problem "eat" p); + then print_endline (print_problem "eat" p); if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then `Finished p else @@ -488,26 +707,19 @@ List.iter (fun l -> prerr_endline (String.concat " " (List.map string_of_var l)) let instantiate p x n = (if `Var x = !bomb - then failwithProblem p ("BOMB (" ^ string_of_nf !bomb ^ ") cannot be instantiated!")); + then failwithProblem p ("BOMB (" ^ string_of_nf p !bomb ^ ") cannot be instantiated!")); + prerr_endline ("stepping on " ^ string_of_var x); + (if List.nth p.arities x <= 0 then failwith "stepped on a varible of arity <= 0"); let p,vars = make_fresh_vars p n in - let p,zero = make_fresh_var p in - let zero = Listx.Nil zero in + let p,zero' = make_fresh_var p in + let zero = Listx.Nil zero' in let args = if n = 0 then zero else Listx.append zero (Listx.from_list vars) in let bs = ref [] in let inst = `Lam(false,`Match(`I(0,Listx.map (lift 1) args),1,bs,[])) in let p = {p with deltas=bs::p.deltas} in - subst_in_problem x inst p -;; - -let compute_special_k tms = - let rec aux k (t: nf) = Pervasives.max k (match t with - | `Lam(b,t) -> aux (k + if b then 1 else 0) t - | `I(n, tms) -> Listx.max (Listx.map (aux 0) tms) - | `Match(t, liftno, bs, args) -> - List.fold_left max 0 (List.map (aux 0) ((t :> nf)::args@List.map snd !bs)) - | `N _ -> 0 - | `Var _ -> 0 - ) in Listx.max (Listx.map (aux 0) tms) + let p = ACMeasure.fix_arities p x (List.map (function `Var x -> x | _ -> assert false) (Listx.to_list args)) in + let p = subst_in_problem x inst p in + p ;; let auto_instantiate (n,p) = @@ -560,21 +772,23 @@ in*) let rec auto_eat (n,({ps} as p)) = prerr_endline "{{{{{{{{ Computing measure before auto_instantiate }}}}}}"; + let p = ACMeasure.fix_arities p (-1) [] in let m = problem_measure p in let (n,p') = auto_instantiate (n,p) in match eat p' with `Finished p -> p | `Continue p -> prerr_endline "{{{{{{{{ Computing measure inafter auto_instantiate }}}}}}"; - let delta = m - problem_measure p' in + let p = ACMeasure.fix_arities p (-1) [] in + let delta = m - problem_measure p in if delta <= 0 then ( - (* failwithProblem p' *) + (* failwithProblem p *) prerr_endline ("Measure did not decrease (delta=" ^ string_of_int delta ^ ")")) else prerr_endline ("$ Measure decreased by " ^ string_of_int delta); - let p' = {p' with steps=(p'.steps - 1)} in - (if p'.steps < 0 then prerr_endline ">>>>>>>>>> STEPS ARE OVER <<<<<<<<<" - (*failwithProblem p' "steps are over. sorry."*) ); + (* let p' = {p' with steps=(p'.steps - 1)} in *) + (* (if p'.steps < 0 then prerr_endline ">>>>>>>>>> STEPS ARE OVER <<<<<<<<<" + (*failwithProblem p' "steps are over. sorry."*) ); *) auto_eat (n,p) ;; @@ -677,7 +891,7 @@ let main problems = if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then begin p end else - let _ = prerr_endline (print_problem "main" p) in + let _ = print_endline (print_problem "main" p) in let x,l = match l with | cmd::l -> cmd,l @@ -702,8 +916,10 @@ let main problems = bomb := `Var (-1); let p_finale = aux p n cmds in let freshno,sigma = p_finale.freshno, p_finale.sigma in - prerr_endline ("------- ------\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 ("------- ------\n " + (* ^ (string_of_int (p.steps - (List.length p_finale.sigma))) ^ " steps of "^ (string_of_int p.steps) ^"." *) + ); + (* print_endline (print_problem "Original problem" p); *) prerr_endline "---------------------"; let l = Array.to_list (Array.init (freshno + 1) string_of_var) in prerr_endline (" BOMB == " ^ print ~l !bomb); @@ -717,7 +933,7 @@ let main problems = (* In this non-recursive version, the intermediate states may containt Matchs *) List.map (fun t -> let t = subst false x inst (t :> nf) in cast_to_i_num_var t) ps) (p.ps :> i_num_var list) sigma in - prerr_endline (print_problem {p with ps= List.map (function t -> cast_to_i_n_var t) ps; freshno}); + print_endline (print_problem {p with ps= List.map (function t -> cast_to_i_n_var t) ps; freshno}); List.iteri (fun i (n,more_args) -> assert (more_args = 0 && n = `N i)) ps ; *) prerr_endline "-------------------"; @@ -778,21 +994,12 @@ let append_zero = | _ -> assert false ;; -let bounds_on_steps all_tms = - let rec aux = function - | `I(k,args) -> Listx.fold_left (fun acc t -> 1 + acc + (aux t)) 0 args - | `Var _ -> 1 - | `Lam (_, t) -> 1 + aux t - | _ -> assert false - in List.fold_right ((+) ++ aux) all_tms 0 -;; type t = problem * int * string list;; let magic_conv ~div ~conv ~nums cmds = let all_tms = (match div with None -> [] | Some div -> [div]) @ nums @ conv in let all_tms, var_names = parse' all_tms in - let steps = bounds_on_steps all_tms in let div, (tms, conv) = match div with | None -> None, list_cut (List.length nums, all_tms) | Some _ -> Some (List.hd all_tms), list_cut (List.length nums, List.tl all_tms) in @@ -800,7 +1007,7 @@ let magic_conv ~div ~conv ~nums cmds = if match div with None -> false | Some div -> List.exists (eta_subterm div) (tms@conv) then ( prerr_endline "--- TEST SKIPPED ---"; - {freshno=0; div=None; conv=[]; ps=[]; sigma=[]; deltas=[]; steps=(-1)}, 0, [] + {freshno=0; div=None; conv=[]; ps=[]; sigma=[]; deltas=[]; arities=[]; special_k=(-1);}, 0, [] ) else let tms = sort_uniq ~compare:eta_compare tms in let special_k = compute_special_k (Listx.from_list all_tms) in (* compute initial special K *) @@ -811,11 +1018,15 @@ let magic_conv ~div ~conv ~nums cmds = let ps = List.map append_zero tms in (* crea lista applicando zeri o dummies *) let freshno = List.length var_names in + let sigma = [] in let deltas = let dummy = `Var (max_int / 2) in - [ ref (Array.to_list (Array.init (List.length ps) (fun i -> i, dummy))) ] in - - {freshno; div; conv; ps; sigma=[] ; deltas; steps}, special_k, cmds + [ ref (Array.to_list (Array.init (List.length ps) (fun i -> i, dummy))) ] in + let p = {freshno; div; conv; ps; sigma; deltas; special_k; arities=[]} in + let arities = + List.mapi (fun i () -> ACMeasure.map_max (ACMeasure.get_arity_of_var p i) ((all_terms p) :> nf list)) (Array.to_list (Array.make (freshno+1) ())) in + let p = {p with arities} in + p, special_k, cmds ;; let magic strings cmds = magic_conv None [] strings cmds;; diff --git a/ocaml/lambda4b.ml b/ocaml/lambda4b.ml new file mode 100644 index 0000000..dbd7396 --- /dev/null +++ b/ocaml/lambda4b.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/measure.ml b/ocaml/measure.ml new file mode 100644 index 0000000..53b0fbc --- /dev/null +++ b/ocaml/measure.ml @@ -0,0 +1,32 @@ +open Num;; +open Lambda4;; + +(* type var = int;; + +type state = { + terms : nf list; + arities : (var * int) list; + freshno : int; + apps : (var * (var list)) list; +} + +let replace = + function + | `Var _ | `Lam _ as t -> t + | `I(v,tms) -> + try + let apps = List.assoc v p.apps in + let hd, tl = ... in + let s, freshvar = mk_freshvar s + [] + aux (mk_apps v (Listx.map )) + with + | Not_found -> `I(v, Listx.map (replace s) tms) + | _ -> assert false +;; + + +let iteration : state -> state = fun s -> + let terms = Util.concat_map (replace s) s.terms in + s;; +*) diff --git a/ocaml/num.ml b/ocaml/num.ml index 6f3cae5..01787b0 100644 --- a/ocaml/num.ml +++ b/ocaml/num.ml @@ -138,7 +138,6 @@ let rec string_of_term l = ;; let print ?(l=[]) = string_of_term l;; -let string_of_nf t = string_of_term [] (t:>nf);; (************ Hereditary substitutions ************************************) @@ -292,3 +291,14 @@ let rec eta_subterm sub t = ;; let eta_subterm (#nf as x) (#nf as y) = eta_subterm x y;; + +let compute_special_k tms = + let rec aux k (t: nf) = Pervasives.max k (match t with + | `Lam(b,t) -> aux (k + if b then 1 else 0) t + | `I(n, tms) -> Listx.max (Listx.map (aux 0) tms) + | `Match(t, liftno, bs, args) -> + List.fold_left max 0 (List.map (aux 0) ((t :> nf)::args@List.map snd !bs)) + | `N _ -> 0 + | `Var _ -> 0 + ) in Listx.max (Listx.map (aux 0) tms) +;; diff --git a/ocaml/num.mli b/ocaml/num.mli index 2f92884..f81e445 100644 --- a/ocaml/num.mli +++ b/ocaml/num.mli @@ -28,7 +28,6 @@ module ToScott : val t_of_nf : nf -> Pure.Pure.t end val print : ?l:string list -> nf -> string -val string_of_nf : [ string val cast_to_i_var : [< nf > `I `Var] -> i_var val cast_to_i_n_var : [< nf > `I `N `Var] -> i_n_var val cast_to_i_num_var : [< nf > `I `N `Match `Var] -> i_num_var @@ -41,3 +40,4 @@ val parse' : string list -> nf list * string list val eta_compare : nf -> nf -> int val eta_eq : [< nf ] -> [< nf ] -> bool val eta_subterm : [< nf ] -> [< nf ] -> bool +val compute_special_k: nf Listx.listx -> int diff --git a/ocaml/ptest.ml b/ocaml/ptest.ml new file mode 100644 index 0000000..8a21229 --- /dev/null +++ b/ocaml/ptest.ml @@ -0,0 +1,16 @@ +open Unix;; +let process_output_to_list2 = fun command -> + let chan = open_process_in command in + let res = ref ([] : string list) in + let rec process_otl_aux () = + let e = input_line chan in + res := e::!res; + process_otl_aux() in + try process_otl_aux () + with End_of_file -> + let stat = close_process_in chan in (List.rev !res,stat) +let cmd_to_list command = + let (l,_) = process_output_to_list2 command in l;; + +let lines = cmd_to_list "tput cols" in +prerr_endline (List.hd (lines));; diff --git a/ocaml/tmp.ml b/ocaml/tmp.ml new file mode 100644 index 0000000..624875f --- /dev/null +++ b/ocaml/tmp.ml @@ -0,0 +1,38 @@ +(((((((v (((a v) w) (((a v) w) v))) (w. c)) (b (a v))) c) (z. a)) (x. (w. (w. c)))) (((a (y c)) ((y c) ((a v) (w (z. a))))) (w. c))) +((((((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 fancy_of_term : nf -> Console.fancyobj = + let open Console in + let of_var level n = + if n < level + then fancy_of_string (string_of_var n) + else (("x" ^ string_of_int (level-n-1)) / ("var" ^ string_of_int (n-level) ^ "")) + in let rec aux level = function + `Var n -> of_var level n + | `N n -> fancy_of_string (string_of_int n) + | `Match(t,bs_lift,bs,args) -> + "([" ^^ aux level (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) + in aux 0 +;; -- 2.39.2