From 4ecc6dd5043fc82ca99f005940896b4ecce4865c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois@bobot.eu> Date: Sun, 20 Jan 2013 14:16:19 +0100 Subject: [PATCH] [Egraph] Use classes instead of term representant --- Makefile | 8 +- src/egraph_simple.ml | 275 +++++++++++++++++----------------------- src/egraph_simple.mli | 11 +- src/term.ml | 238 ++++++++++++++++++++++++++-------- src/term.mli | 52 ++++++-- src/util/exn_printer.ml | 13 +- tests/tests_uf.ml | 107 ++++++++++------ 7 files changed, 419 insertions(+), 285 deletions(-) diff --git a/Makefile b/Makefile index e48aaad25..3bd2ea635 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,17 @@ -.PHONY: tests tests.native +.PHONY: tests tests.native tests_debug all: tests tests.native: - ocamlbuild tests/tests.native -I src -I src/util -package oUnit + ocamlbuild tests/tests.native -I src -I src/util -package oUnit \ + -tag annot -tag debug SEEDTEST=1 2 3 4 5 6 7 tests: tests.native ./tests.native + +tests_debug: tests.native + OCAMLRUNPARAM=b ./tests.native -verbose --debug egraph_simple --debug unionfind \ No newline at end of file diff --git a/src/egraph_simple.ml b/src/egraph_simple.ml index fa943e329..4a01229f0 100644 --- a/src/egraph_simple.ml +++ b/src/egraph_simple.ml @@ -35,192 +35,155 @@ let debug = Debug.register_info_flag ~desc:"for the simple version of the egraph" "egraph_simple" -module UnionFind (* simple *) : -sig type t - val empty: t - val find: exn -> t -> Term.t -> Term.t - val union: t -> Term.t -> Term.t -> t - val iter: (Term.t -> Term.t -> unit) -> t -> unit -end = -struct - type t = Term.t Term.M.t - - let empty = Term.M.empty - - let rec find exn uf t = - let r = Term.M.find_exn exn t uf in - if Term.equal t r then r else find exn uf r - - (** union but t2 becomes the representatives *) - let union uf t1 t2 = Term.M.add t1 t2 uf - - let iter = Term.M.iter -end - -type env = - { - repr : UnionFind.t; - (** representants represent themselves. The signatures (as in DST) - are also in this structure *) - use : Term.S.t Term.M.t; - (** keep the successors (in the egraph) of the terms *) - added : Term.S.t; - (** invariant the values in repr are always in added *) - } - -let empty_env = { repr = UnionFind.empty; - use = Term.M.empty; - added = Term.S.empty } +module UnionFind = Term.UnionFind +module Cl = Term.Cl + +type env = UnionFind.t (** Get the representative or raise NoRepr if the node have never be added *) exception NoRepr -let repr env t = UnionFind.find NoRepr env.repr t - -(** Test if a node is not just a signature *) -let is_added env t = Term.S.mem t env.added - -(** Return the successors of a node *) -let use env t = - assert (Term.equal (repr env t) t); - (** Strange if it's used not with a representative *) - Term.M.find_def Term.S.empty t env.use +let repr env t = UnionFind.repr NoRepr env t +let has_repr env t = + try ignore (repr env t:Term.value); true + with NoRepr -> false +let print_repr = UnionFind.print_repr -(** Normalize the term and update the use *) -let rec normalize env t = - try - repr env t,env - with NoRepr -> - let t',env = match t.Term.value with - | Term.Cst _ -> t,env +(** Normalize the term and update the use + precondition cl is_findable +*) +let rec normalize env cl = + if has_repr env cl then cl,env + else begin + Debug.dprintf debug + "[EGraph] normalize @[%a@]@." + Cl.print cl; + let cl',env = match UnionFind.base cl with + | Term.Cst _ as v -> + let env = UnionFind.set_repr env cl v in + cl,env | Term.App (f,g) -> - let f,env = normalize env f in - let g,env = normalize env g in - let t' = Term.app f g in - try repr env t',env - with NoRepr -> - match t.Term.value with - | Term.Cst _ -> t',env - | Term.App (f,g) -> - let add_use use t arg = - Term.M.change (function - | None -> Some (Term.S.singleton t) - | Some s -> Some (Term.S.add t s)) arg use in - t',{env with - use = add_use (add_use env.use t f) t g; - repr = UnionFind.union env.repr t' t'} + let clf,env = normalize env (UnionFind.find env f) in + let clg,env = normalize env (UnionFind.find env g) in + let v = Term.App(clf,clg) in + let cl,env = UnionFind.basecl env v in + if has_repr env cl then cl,env + else + let env = UnionFind.add_use env cl v clf in + let env = UnionFind.add_use env cl v clg in + let env = UnionFind.set_repr env cl v in + cl,env in - t',{env with repr = UnionFind.union env.repr t t'} + let env = UnionFind.union env cl cl' in + Debug.dprintf debug + "[EGraph] normalized @[%a@] as @[%a@]@." + Cl.print cl (print_repr env) cl; + cl',env + end (** really add the term, can be used as representative *) -let add env t = - let rec tag env t = - if is_added env t then env +let add env cl = + let cl',env = normalize env cl in + Debug.dprintf debug + "[EGraph] Add @[@[%a@]@ as@ @[%a@]@]@." + (print_repr env) cl (print_repr env) cl'; + let rec tag env cl = + if UnionFind.is_added env cl then env else - let env = {env with added = Term.S.add t env.added} in - match t.Term.value with + let env = UnionFind.added env cl in + match repr env cl with | Term.Cst _ -> env | Term.App (f,g) -> tag (tag env f) g in - let t',env = normalize env t in - Debug.dprintf debug - "[EGraph] Add @[@[%a@]@ as@ @[%a@]@]@." - Term.print t Term.print t'; - t',tag env t' + cl',tag env cl' -let rec is_equal env t1 t2 = - let t1' = repr env t1 in - let t2' = repr env t2 in +let rec is_equal env cl1 cl2 = + assert (UnionFind.is_added env cl1); + assert (UnionFind.is_added env cl2); + let cl1' = UnionFind.find env cl1 in + let cl2' = UnionFind.find env cl2 in Debug.dprintf debug "[EGraph] @[@[%a@]@,{@[%a@]} =?@ @[%a@]@,{@[%a@]}@]@." - Term.print t1 Term.print t1' Term.print t2 Term.print t2'; - Term.equal t1' t2' + (print_repr env) cl1 (print_repr env) cl1' (print_repr env) cl2 + (print_repr env) cl2'; + Cl.equal cl1' cl2' (** t1 -> t2, t1 must be a direct subterm of t3 *) let subst t1 t2 t3 = - match t3.Term.value with - | Term.Cst _ -> assert (Term.equal t1 t3); t2 + match t3 with + | Term.Cst _ -> assert false; (** can't substitute somthing without leaves *) | Term.App(f,g) -> - assert ( Term.equal t1 f || Term.equal t1 g); - let subst t1 t2 arg = if Term.equal t1 arg then t2 else arg in - Term.app (subst t1 t2 f) (subst t1 t2 g) - -let rec equal_aux queue env t1 t2 = - let t1 = repr env t1 in - let t2 = repr env t2 in - if Term.equal t1 t2 then env else begin + assert ( Cl.equal t1 f || Cl.equal t1 g); + let subst t1 t2 arg = if Cl.equal t1 arg then t2 else arg in + Term.App (subst t1 t2 f, subst t1 t2 g) + +exception ExitEnv of UnionFind.t + +let rec equal_aux nb queue env cl1 cl2 = + let cl1 = UnionFind.find env cl1 in + let cl2 = UnionFind.find env cl2 in + if Cl.equal cl1 cl2 then env else begin Debug.dprintf debug - "[EGraph] @[@[%a@] =@ @[%a@]@]@." Term.print t1 Term.print t2; - (* t1 -> t2 *) - let use1 = use env t1 in - let env = {env with repr = UnionFind.union env.repr t1 t2} in - let fold parent env = - (** We use the version in use because it must have t1 as leaves *) - let parent' = subst t1 t2 parent in - Debug.dprintf debug - "[EGraph] @[%a[@[%a@]->@[%a@]]@]@." - Term.print parent Term.print t1 Term.print t2; - (** can be an old parent or even not added ( but once normalized ) *) - let parent = repr env parent in - let parent',env = normalize env parent' in - (** choose which one becomes representants p1 -> p2 *) - let p1,p2 = if not (is_added env parent') then - begin - (** we choose parent' -> parent since parent' is a node not added - we need to use only representant that have been added - (for termination) - *) - assert (is_added env parent); - Debug.dprintf debug - "[EGraph] @[@[%a@] !->@ @[%a@]@]@." - Term.print parent' Term.print parent; - parent', parent - end - else - begin - shufflep (parent, parent') - end - in - if p1 != p2 then Queue.push (p1,p2) queue; - env + "[EGraph] Equal_Aux @[@[%a@] =>@ @[%a@]@]@." + (print_repr env) cl1 (print_repr env) cl2; + (* cl1 -> cl2 *) + let fold clparent vparent env = + try + (** First we take the representative class + and then we verify that the represnentative doesn't change *) + let clparent = UnionFind.find env clparent in + (* if not (Term.equal vparent (repr env clparent)) then raise (ExitEnv env); *) + (** We use the version in use because it must have cl1 as leaves *) + let clparent',env = UnionFind.basecl env (subst cl1 cl2 vparent) in + Debug.dprintf debug + "[EGraph] @[%a[@[%a@]->@[%a@]]@]@." + (print_repr env) clparent (print_repr env) cl1 (print_repr env) cl2; + let clparent',env = normalize env clparent' in + if clparent != clparent' then Queue.push (clparent,clparent') queue; + env + with ExitEnv env -> + Debug.dprintf debug + "[EGraph] Use skipped %a %a@." + (print_repr env) clparent (UnionFind.print_value env) vparent; + env + in + let use1 = UnionFind.fold_use fold env cl1 in + (** choose which one becomes representants p1 -> p2 *) + let env = if not (UnionFind.is_added env cl2) then + begin + (** we choose parent' -> parent since parent' is a node not added + we need to use only representant that have been added + (for termination) + *) + assert (UnionFind.is_added env cl1); + Debug.dprintf debug + "[EGraph] @[@[%a@] !->@ @[%a@]@]@." + (print_repr env) cl2 (print_repr env) cl1; + let env = UnionFind.set_repr env cl1 (repr env cl2) in + let env = UnionFind.union env cl2 cl1 in + env + end + else + begin + let env = UnionFind.union env cl1 cl2 in + env + end in - let env = Term.S.fold fold use1 env in + let env = use1 env in if Queue.is_empty queue then env else - let (t1,t2) = Queue.pop queue in - equal_aux queue env t1 t2 + let (cl1,cl2) = Queue.pop queue in + if !nb = 0 then invalid_arg ("Two many step? Cycle?"); + decr nb; + equal_aux nb queue env cl1 cl2 end let equal env t1 t2 = let t1,t2 = shufflep (t1,t2) in + let nb = ref 100 in let queue = Queue.create () in - equal_aux queue env t1 t2 - -let exportdot filename env = - let cout = open_out filename in - let fmt = Format.formatter_of_out_channel cout in - Format.fprintf fmt "@[<2>digraph G {@\n"; - UnionFind.iter - (fun k r -> Format.fprintf fmt "\"@[<h>%a@]\" -> \"@[<h>%a@]\";@\n" - Term.print k Term.print r) - env.repr; - Term.M.iter - (fun k s -> - Term.S.iter (fun r -> - Format.fprintf fmt "\"@[<h>%a@]\"@ -> \"@[<h>%a@]\"@ \ - [@[style=\"dashed\",@ constraint=false@],@ \ - color=\"gray\"];@\n" - Term.print k Term.print r) s) - env.use; - Term.S.iter - (fun s -> - Format.fprintf fmt "\"@[<h>%a@]\"@ [@[style=\"bold\"@]];@\n" - Term.print s) - env.added; - Format.fprintf fmt "}@]@."; - Format.pp_print_flush fmt (); - close_out cout + equal_aux nb queue env t1 t2 let () = Exn_printer.register (fun fmt exn -> match exn with diff --git a/src/egraph_simple.mli b/src/egraph_simple.mli index f51b9d950..86344acd6 100644 --- a/src/egraph_simple.mli +++ b/src/egraph_simple.mli @@ -23,11 +23,8 @@ val debug: Debug.flag -type env +type env = Term.UnionFind.t -val empty_env: env -val add: env -> Term.t -> Term.t * env -val is_equal: env -> Term.t -> Term.t -> bool -val equal: env -> Term.t -> Term.t -> env - -val exportdot: string -> env -> unit +val add: env -> Term.cl -> Term.cl * env +val is_equal: env -> Term.cl -> Term.cl -> bool +val equal: env -> Term.cl -> Term.cl -> env diff --git a/src/term.ml b/src/term.ml index 29f330be3..405224794 100644 --- a/src/term.ml +++ b/src/term.ml @@ -22,77 +22,203 @@ open Stdlib + +let debug = Debug.register_info_flag + ~desc:"for the simple version of uf" + "unionfind" + type tag = int -type t = { - tag : int; - value : value; +type cl = { + tag : int; + base : (** not the representative *) value; } and value = | Cst of Strings.Hashcons.t - | App of t * t - -type node = t - -module Node = Hashcons.Make( - struct - type t = node - - let hash n = - match n.value with - | Cst i -> 2 * (i :> int) - | App(g,f) -> 3 * g.tag + 5 * f.tag - - let equal n m = - match n.value, m.value with - | Cst i, Cst j -> i = j - | App (g1,f1), App(g2,f2) -> g1.tag = g2.tag && f1.tag = f2.tag - | _ -> false + | App of cl * cl + + +let equal n m = + match n, m with + | Cst i, Cst j -> i = j + | App (g1,f1), App(g2,f2) -> g1.tag = g2.tag && f1.tag = f2.tag + | _ -> false + +module ClHashcons = struct + type t = cl + + let hash n = + match n.base with + | Cst i -> 2 * (i :> int) + | App(g,f) -> 3 * g.tag + 5 * f.tag + + let equal n m = + match n.base, m.base with + | Cst i, Cst j -> i = j + | App (g1,f1), App(g2,f2) -> g1.tag = g2.tag && f1.tag = f2.tag + | _ -> false + + let tag tag node = {node with tag} +end + +module Cl = struct + type t = cl + module Cl = MakeMSH(struct type t = cl let tag t = t.tag end) + include Cl.T + let rec print fmt cl = Format.fprintf fmt "@[@@%i@]" cl.tag + include Cl +end - let tag tag node = {node with tag} - end -) -let dumb_tag = -1 -let cst s = Node.hashcons({tag = dumb_tag; - value = Cst (Strings.Hashcons.make s)}) -let app f g = Node.hashcons({tag = dumb_tag; value = App(f,g)}) +module UnionFind = +struct -let rec print fmt k = - match k.value with - | Cst i -> Strings.Hashcons.print fmt i - | App (f,g) -> Format.fprintf fmt "(@[%a@],@,@[%a@])" print f print g + module H = Hashcons.Make(ClHashcons) + type t = { + eq : cl Cl.M.t; + (** stocking value for others *) + repr : value Cl.M.t; + use : value Cl.M.t Cl.M.t; + added : Cl.S.t; + } -let appl f l = - let rec aux = function - | [] -> assert false - | [a] -> a - | a::l -> app a (aux l) in - app f (aux l) + let repr exn t cl = Cl.M.find_exn exn cl t.repr -let fun1 s = - let f = cst s in - (fun x -> app f x) + let rec print_value nb env fmt v = + match v with + | Cst i -> Format.fprintf fmt "%a" + Strings.Hashcons.print i + | App (f,g) -> Format.fprintf fmt "(@[%a@],@,@[%a@])" + (print_repr nb env) f (print_repr nb env) g -let fun2 s = - let f = cst s in - (fun x1 x2 -> appl f [x1;x2]) -let fun3 s = - let f = cst s in - (fun x1 x2 x3 -> appl f [x1;x2;x3]) + and print_repr nb env fmt k = + if nb = 0 then Cl.print fmt k else + try + Format.fprintf fmt "%a" + (print_value (nb-1) env) (repr Exit env k) + with Exit -> + Format.pp_print_string fmt "<NoRepr>" -let fun4 s = - let f = cst s in - (fun x1 x2 x3 x4 -> appl f [x1;x2;x3;x4]) + let print_value env fmt v = print_value 10 env fmt v + let print_repr env fmt k = + Format.fprintf fmt "%a[%a]" + Cl.print k (print_repr 10 env) k -let fun5 s = - let f = cst s in - (fun x1 x2 x3 x4 x5 -> appl f [x1;x2;x3;x4;x5]) + let empty = + { eq = Cl.M.empty; + repr = Cl.M.empty; + use = Cl.M.empty; + added = Cl.M.empty; + } + + (** union but t2 becomes the representatives *) + let rec find t cl = + let r = Cl.M.find cl t.eq in + if Cl.T.equal cl r then r else find t r + + let rec is_findable t cl = Cl.equal (find t cl) cl + + let union t cl1 cl2 = + Debug.dprintf debug "[Uf]@[ Union@ @[%a@]@ @[%a@]@]@\n" + (print_repr t) cl1 (print_repr t) cl2; + { t with eq = Cl.M.add cl1 cl2 t.eq } + + let iter f t = Cl.M.iter f t.eq + + let basecl t v = + let basecl = H.hashcons({tag = -1 (** dumb *); base = v}) in + try + find t basecl, t + with Not_found -> + basecl, {t with eq = Cl.M.add basecl basecl t.eq} + let base cl = cl.base + + + let cst t s = basecl t (Cst (Strings.Hashcons.make s)) + let app t f g = basecl t (App(f,g)) + + + let appl t f l = + let rec aux t = function + | [] -> assert false + | [a] -> a,t + | a::l -> let l,t = aux t l in app t a l in + let l,t = aux t l in + app t f l + + let fun1 t s = + let f,t = cst t s in + (fun t x -> app t f x), t + + let fun2 t s = + let f,t = cst t s in + (fun t x1 x2 -> appl t f [x1;x2]), t + + let fun3 t s = + let f,t = cst t s in + (fun t x1 x2 x3 -> appl t f [x1;x2;x3]), t + + let fun4 t s = + let f,t = cst t s in + (fun t x1 x2 x3 x4 -> appl t f [x1;x2;x3;x4]), t + + let fun5 t s = + let f,t = cst t s in + (fun t x1 x2 x3 x4 x5 -> appl t f [x1;x2;x3;x4;x5]), t + + + (** For others *) + + + let set_repr t cl v = {t with repr = Cl.M.add cl v t.repr} + + let fold_use f t cl acc = Cl.M.fold f (Cl.M.find_def Cl.M.empty cl t.use) acc + + let add_use t cl v arg = + {t with use = + Cl.M.change (function + | None -> Some (Cl.M.singleton cl v) + | Some m -> (* assert( not (Cl.M.mem cl m) );*) + Some (Cl.M.add cl v m)) arg t.use} + + let is_added t cl = Cl.S.mem cl t.added + + let added t cl = {t with added = Cl.S.add cl t.added} + + + + let exportdot filename env = + let cout = open_out filename in + let fmt = Format.formatter_of_out_channel cout in + Format.fprintf fmt "@[<2>digraph G {@\n"; + Cl.M.iter + (fun k r -> Format.fprintf fmt "@[<h>\"%a\"@] -> @[<h>\"%a\"@];@\n" + Cl.print k Cl.print r) + env.eq; + Cl.M.iter + (fun k s -> + Cl.M.iter (fun r _ -> + Format.fprintf fmt "@[<h>\"%a\"@]@ -> @[<h>\"%a\"@]@ \ + [@[style=\"dashed\",@ constraint=false@],@ \ + color=\"gray\"];@\n" + Cl.print k Cl.print r) s) + env.use; + Cl.M.iter + (fun k _ -> + Format.fprintf fmt "@[<h>\"%a\"@]@ [@[label=@[<h>\"%a\"@]@]];@\n" + Cl.print k (print_repr env) k) + env.repr; + Cl.S.iter + (fun s -> + Format.fprintf fmt "@[<h>\"%a\"@]@ [@[style=\"bold\"@]];@\n" + Cl.print s) + env.added; + Format.fprintf fmt "}@]@."; + Format.pp_print_flush fmt (); + close_out cout -module MSH = MakeMSH(struct type t = node let tag t = t.tag end) -include MSH -include MSH.T +end diff --git a/src/term.mli b/src/term.mli index d6987b4bb..6b84598f8 100644 --- a/src/term.mli +++ b/src/term.mli @@ -24,24 +24,48 @@ open Stdlib type tag = private int -type t = private { - tag : tag; - value : value; -} +type cl -and value = private +type value = | Cst of Strings.Hashcons.t - | App of t * t + | App of cl * cl -include Datatype with type t := t +val equal: value -> value -> bool +module UnionFind (* simple *) : +sig + type t + val basecl: t -> value -> cl * t + val base: cl -> value + val empty: t + val find: t -> cl -> cl + val is_findable: t -> cl -> bool (* find cl = cl *) + val union: t -> cl -> cl -> t + val iter: (cl -> cl -> unit) -> t -> unit -val cst: string -> t -val app: t -> t -> t + val cst: t -> string -> cl * t + val app: t -> cl -> cl -> cl * t + val fun1 : t -> string -> (t -> cl -> cl * t) * t + val fun2 : t -> string -> (t -> cl -> cl -> cl * t) * t + val fun3 : t -> string -> (t -> cl -> cl -> cl -> cl * t) * t + val fun4 : t -> string -> (t -> cl -> cl -> cl -> cl -> cl * t) * t + val fun5 : t -> string -> (t -> cl -> cl -> cl -> cl -> cl -> cl * t) * t -val fun1 : string -> (t -> t) -val fun2 : string -> (t -> t -> t) -val fun3 : string -> (t -> t -> t -> t) -val fun4 : string -> (t -> t -> t -> t -> t) -val fun5 : string -> (t -> t -> t -> t -> t -> t) + val repr: exn -> t -> cl -> value + val set_repr: t -> cl -> value -> t + val print_repr: t -> Format.formatter -> cl -> unit + val print_value: t -> Format.formatter -> value -> unit + + val add_use : t -> cl -> value -> cl -> t + val fold_use : (cl -> value -> 'a -> 'a) -> t -> cl -> 'a -> 'a + val is_added : t -> cl -> bool + val added : t -> cl -> t + + + val exportdot: string -> t -> unit + +end + + +module Cl : Datatype with type t = cl diff --git a/src/util/exn_printer.ml b/src/util/exn_printer.ml index d570c9e20..3c452c4f1 100644 --- a/src/util/exn_printer.ml +++ b/src/util/exn_printer.ml @@ -15,12 +15,6 @@ let exn_printers = (Stack.create () : (Format.formatter -> exn -> unit) Stack.t) let register exn_printer = Stack.push exn_printer exn_printers; - Printexc.register_printer (fun exn -> Some (Pp.string_of exn_printer exn)) - -let () = - let all_exn_printer fmt exn = - Format.fprintf fmt "anomaly: %s" (Printexc.to_string exn) in - register all_exn_printer exception Exit_loop @@ -30,9 +24,10 @@ let exn_printer fmt exn = Format.fprintf fmt "@[%a@]" f exn; raise Exit_loop with - | Exit_loop -> raise Exit_loop + | Exit_loop -> raise exn | _ -> () in - try Stack.iter test exn_printers - with Exit_loop -> () + Stack.iter test exn_printers +let () = + Printexc.register_printer (fun exn -> Some (Pp.string_of exn_printer exn)) diff --git a/tests/tests_uf.ml b/tests/tests_uf.ml index 812370f0d..d19e09b00 100644 --- a/tests/tests_uf.ml +++ b/tests/tests_uf.ml @@ -1,15 +1,18 @@ open OUnit -let f = Term.cst "f" -let g = Term.cst "g" - -let a = Term.cst "a" -let b = Term.cst "b" -let c = Term.cst "c" - module Tests(E: module type of Egraph_simple) = struct open E -let env = empty_env + +module Uf = Term.UnionFind + +let env = Uf.empty + +let f,env = Uf.fun1 env "f" +let g,env = Uf.fun2 env "g" + +let a,env = Uf.cst env "a" +let b,env = Uf.cst env "b" +let c,env = Uf.cst env "c" let a,env = add env a let b,env = add env b @@ -28,30 +31,40 @@ let trans () = let env = (equal (equal env a b) b c) in let basic = "Basic" >::: ["empty" >:: empty; "tauto" >:: tauto; "trans" >:: trans] -let fa,env = add env (Term.app f a) -let fb,env = add env (Term.app f b) +let adde (c,env) = add env c + +let fa,env = adde (f env a) +let fb,env = adde (f env b) let refl () = assert_bool "f(a) = f(a)" (is_equal env fa fa) let empty () = assert_bool "f(a) != f(b)" (not (is_equal env fa fb)) let congru () = assert_bool "a = b => f(a) = f(b)" (is_equal (equal env a b) fa fb) -let ffa,env = add env (Term.app f fa) -let ffb,env = add env (Term.app f fb) +let ffa,env = adde (f env fa) +let ffb,env = adde (f env fb) let _2level () = assert_bool "a = b => f(f(a)) = f(f(b))" (is_equal (equal env a b) ffa ffb) -let ffc,env = add env (Term.app f (Term.app f c)) +let fe (c,env) = f env c + +let ffc,env = adde (fe (f env c)) let _2level' () = assert_bool "a = c => f(f(a)) = f(f(c))" (is_equal (equal env a c) ffa ffc) let bigger () = - let env = empty_env in - let rec bf n = if n < 1 then a else (Term.app f (bf (n-1))) in - let fffa, env = add env (bf 3) in - let fffffa, env = add env (bf 5) in + let env = Uf.empty in + let f,env = Uf.fun1 env "f" in + let a,env = Uf.cst env "a" in + let fe (c,env) = f env c in + let rec bf env n = if n < 1 then a,env else (fe (bf env (n-1))) in + let fffa, env = adde (bf env 3) in + let fffffa, env = adde (bf env 5) in + Uf.exportdot "bigger0.dot" env; let env = equal env a fffa in + Uf.exportdot "bigger1.dot" env; let env = equal env fffffa a in + Uf.exportdot "bigger2.dot" env; assert_bool "a = f(f(f(a))) => f(f(f(f(f(a))))) = a => f(a) = a" (is_equal env fa a) @@ -61,15 +74,15 @@ let congru1 = "Congru 1 arg" >::: ["refl" >:: refl; "congru" >:: congru; "bigger" >:: bigger] -let gab,env = add env (Term.app g (Term.app a b)) -let gaa,env = add env (Term.app g (Term.app a a)) -let gbb,env = add env (Term.app g (Term.app b b)) +let gab,env = adde (g env a b) +let gaa,env = adde (g env a a) +let gbb,env = adde (g env b b) let refl () = assert_bool "g(a,b) = g(a,b)" (is_equal env gab gab) let congru () = assert_bool "a = b => g(a,b) = g(a,a)" (is_equal (equal env a b) gab gaa) let _2level () = - let ggabb,env = add env (Term.app g (Term.app gab b)) in + let ggabb,env = adde (g env gab b) in (* f(a,b) = a, show f(f(a,b),b) = a *) assert_bool "g(a,b) = a => g(g(a,b),b) = a" (is_equal (equal env gab a) ggabb a) @@ -92,31 +105,43 @@ let is_equal env x y = let altergo1 = "h(x)=x and g(a,x)=a -> g(g(a,h(x)),x)=a" >:: fun () -> - let env = empty_env in - let h = Term.fun1 "h" in - let g = Term.fun2 "g" in - let x = Term.cst "x" in - let a = Term.cst "a" in - let env = equal env (h x) x in - let env = equal env (g a x) a in - assert_bool "" - (is_equal env (g (g a (h x)) x) a) + let env = Uf.empty in + let h,env = Uf.fun1 env "h" in + let g,env = Uf.fun2 env "g" in + let x,env = Uf.cst env "x" in + let a,env = Uf.cst env "a" in + let hx,env = h env x in + let env = equal env hx x in + let gax, env = g env a x in + let env = equal env gax a in + let hx, env = h env x in + let gahx, env = g env a hx in + let ggahxx, env = g env gahx x in + assert_bool "" (is_equal env ggahxx a) let altergo2 = "f(f(f(a)))=a and f(f(f(f(f(a)))))=a and g(x,y)=x -> \ h(g(g(x,y),y),a)=h(x,f(a))" >:: fun () -> - let env = empty_env in - let f = Term.fun1 "f" in - let h = Term.fun2 "h" in - let g = Term.fun2 "g" in - let x = Term.cst "x" in - let y = Term.cst "y" in - let a = Term.cst "a" in - let env = equal env (f (f (f a))) a in - let env = equal env (f (f (f (f (f a))))) a in - let env = equal env (g x y) x in - assert_bool "" (is_equal env (h (g (g x y) y) a) (h x (f a))) + let env = Uf.empty in + let f,env = Uf.fun1 env "f" in + let h,env = Uf.fun2 env "h" in + let g,env = Uf.fun2 env "g" in + let x,env = Uf.cst env "x" in + let y,env = Uf.cst env "y" in + let a,env = Uf.cst env "a" in + let rec bf env n = if n < 1 then a,env else (fe (bf env (n-1))) in + let fffa, env = bf env 3 in + let env = equal env fffa a in + let fffffa, env = bf env 5 in + let env = equal env fffffa a in + let gxy, env = g env x y in + let env = equal env gxy x in + let ggxyy, env = g env gxy y in + let hggxyya, env = h env ggxyy a in + let fa, env = f env a in + let hxfa, env = h env x fa in + assert_bool "" (is_equal env hggxyya hxfa) -- GitLab