feat(cc): adapt to the new CC_view

This commit is contained in:
Simon Cruanes 2022-08-08 21:22:48 -04:00
parent 2a8eb0c166
commit f17e689a3c
No known key found for this signature in database
GPG key ID: EBFFF6F283F3A2B4
13 changed files with 19 additions and 669 deletions

View file

@ -1,6 +1,6 @@
open Types_ open Types_
type view_as_cc = Term.t -> (Const.t, Term.t, Term.t Iter.t) View.t type view_as_cc = Term.t -> (Const.t, Term.t, Term.t list) CC_view.t
type e_node = E_node.t type e_node = E_node.t
(** A node of the congruence closure *) (** A node of the congruence closure *)
@ -165,7 +165,7 @@ end
(* compute up-to-date signature *) (* compute up-to-date signature *)
let update_sig (s : signature) : Signature.t = let update_sig (s : signature) : Signature.t =
View.map_view s ~f_f:(fun x -> x) ~f_t:find_ ~f_ts:(List.map find_) CC_view.map_view s ~f_f:(fun x -> x) ~f_t:find_ ~f_ts:(List.map find_)
(* find whether the given (parent) term corresponds to some signature (* find whether the given (parent) term corresponds to some signature
in [signatures_] *) in [signatures_] *)
@ -466,19 +466,19 @@ and compute_sig0 (self : t) (n : e_node) : Signature.t option =
| Eq (a, b) -> | Eq (a, b) ->
let a = deref_sub a in let a = deref_sub a in
let b = deref_sub b in let b = deref_sub b in
return @@ View.Eq (a, b) return @@ CC_view.Eq (a, b)
| Not u -> return @@ View.Not (deref_sub u) | Not u -> return @@ CC_view.Not (deref_sub u)
| App_fun (f, args) -> | App_fun (f, args) ->
let args = args |> Iter.map deref_sub |> Iter.to_list in let args = List.map deref_sub args in
if args <> [] then if args <> [] then
return @@ View.App_fun (f, args) return @@ CC_view.App_fun (f, args)
else else
None None
| App_ho (f, a) -> | App_ho (f, a) ->
let f = deref_sub f in let f = deref_sub f in
let a = deref_sub a in let a = deref_sub a in
return @@ View.App_ho (f, a) return @@ CC_view.App_ho (f, a)
| If (a, b, c) -> return @@ View.If (deref_sub a, deref_sub b, deref_sub c) | If (a, b, c) -> return @@ CC_view.If (deref_sub a, deref_sub b, deref_sub c)
let[@inline] add_term self t : e_node = add_term_rec_ self t let[@inline] add_term self t : e_node = add_term_rec_ self t
let mem_term = mem let mem_term = mem
@ -950,19 +950,9 @@ module Make (A : ARG) : BUILD = struct
create_ ?stat ?size tst proof ~view_as_cc:A.view_as_cc create_ ?stat ?size tst proof ~view_as_cc:A.view_as_cc
end end
module Default = struct module Default = Make (Sidekick_core.Default_cc_view)
include Make (struct
let view_as_cc (t : Term.t) : _ View.t =
let f, args = Term.unfold_app t in
match Term.view f, args with
| _, [ _; t; u ] when Term.is_eq f -> View.Eq (t, u)
| _ ->
(match Term.view t with
| Term.E_app (f, a) -> View.App_ho (f, a)
| Term.E_const c -> View.App_fun (c, Iter.empty)
| _ -> View.Opaque t)
end)
end
let create (module A : ARG) ?stat ?size tst proof : t = let create (module A : ARG) ?stat ?size tst proof : t =
create_ ?stat ?size tst proof ~view_as_cc:A.view_as_cc create_ ?stat ?size tst proof ~view_as_cc:A.view_as_cc
let create_default = Default.create

View file

@ -255,7 +255,7 @@ val pop_levels : t -> int -> unit
val get_model : t -> E_node.t Iter.t Iter.t val get_model : t -> E_node.t Iter.t Iter.t
(** get all the equivalence classes so they can be merged in the model *) (** get all the equivalence classes so they can be merged in the model *)
type view_as_cc = Term.t -> (Const.t, Term.t, Term.t Iter.t) View.t type view_as_cc = Term.t -> (Const.t, Term.t, Term.t list) CC_view.t
(** Arguments to a congruence closure's implementation *) (** Arguments to a congruence closure's implementation *)
module type ARG = sig module type ARG = sig
@ -275,7 +275,6 @@ module type BUILD = sig
end end
module Make (_ : ARG) : BUILD module Make (_ : ARG) : BUILD
module Default : BUILD
val create : val create :
(module ARG) -> (module ARG) ->
@ -291,6 +290,10 @@ val create :
as well. as well.
*) *)
val create_default :
?stat:Stat.t -> ?size:[ `Small | `Big ] -> Term.store -> Proof_trace.t -> t
(** Same as {!create} but with the default CC view *)
(**/**) (**/**)
module Debug_ : sig module Debug_ : sig

View file

@ -1,4 +1,3 @@
open Sidekick_core
module View = View module View = View
module E_node = E_node module E_node = E_node
module Expl = Expl module Expl = Expl

View file

@ -1,7 +1,5 @@
(** Congruence Closure Implementation *) (** Congruence Closure Implementation *)
open Sidekick_core
module type DYN_MONOID_PLUGIN = Sigs_plugin.DYN_MONOID_PLUGIN module type DYN_MONOID_PLUGIN = Sigs_plugin.DYN_MONOID_PLUGIN
module type MONOID_PLUGIN_ARG = Sigs_plugin.MONOID_PLUGIN_ARG module type MONOID_PLUGIN_ARG = Sigs_plugin.MONOID_PLUGIN_ARG
module type MONOID_PLUGIN_BUILDER = Sigs_plugin.MONOID_PLUGIN_BUILDER module type MONOID_PLUGIN_BUILDER = Sigs_plugin.MONOID_PLUGIN_BUILDER

View file

@ -1,337 +0,0 @@
open Sidekick_core
module CC_view = Sidekick_cc.View
module type ARG = sig
val view_as_cc : Term.t -> (Const.t, Term.t, Term.t Iter.t) CC_view.t
end
module type S = sig
type t
val create : Term.store -> t
val clear : t -> unit
val add_lit : t -> Term.t -> bool -> unit
val check_sat : t -> bool
val classes : t -> Term.t Iter.t Iter.t
end
module Make (A : ARG) = struct
open CC_view
module T = Term
module T_tbl = Term.Tbl
type node = {
n_t: Term.t;
mutable n_next: node; (* next in class *)
mutable n_size: int; (* size of class *)
mutable n_parents: node list;
mutable n_root: node; (* root of the class *)
}
type signature = (Const.t, node, node list) CC_view.t
module Node = struct
type t = node
let[@inline] equal (n1 : t) n2 = T.equal n1.n_t n2.n_t
let[@inline] hash (n : t) = T.hash n.n_t
let[@inline] size (n : t) = n.n_size
let[@inline] is_root n = n == n.n_root
let[@inline] root n = n.n_root
let[@inline] term n = n.n_t
let pp out n = T.pp_debug out n.n_t
let add_parent (self : t) ~p : unit = self.n_parents <- p :: self.n_parents
let make (t : T.t) : t =
let rec n =
{ n_t = t; n_size = 1; n_next = n; n_parents = []; n_root = n }
in
n
(* iterate over the class *)
let iter_cls (n0 : t) f : unit =
let rec aux n =
f n;
let n' = n.n_next in
if equal n' n0 then
()
else
aux n'
in
aux n0
end
module Signature = struct
type t = signature
let equal (s1 : t) s2 : bool =
match s1, s2 with
| Bool b1, Bool b2 -> b1 = b2
| App_fun (f1, []), App_fun (f2, []) -> Const.equal f1 f2
| App_fun (f1, l1), App_fun (f2, l2) ->
Const.equal f1 f2 && CCList.equal Node.equal l1 l2
| App_ho (f1, a1), App_ho (f2, a2) -> Node.equal f1 f2 && Node.equal a1 a2
| Not n1, Not n2 -> Node.equal n1 n2
| If (a1, b1, c1), If (a2, b2, c2) ->
Node.equal a1 a2 && Node.equal b1 b2 && Node.equal c1 c2
| Eq (a1, b1), Eq (a2, b2) -> Node.equal a1 a2 && Node.equal b1 b2
| Opaque u1, Opaque u2 -> Node.equal u1 u2
| Bool _, _
| App_fun _, _
| App_ho _, _
| If _, _
| Eq _, _
| Opaque _, _
| Not _, _ ->
false
let hash (s : t) : int =
let module H = CCHash in
match s with
| Bool b -> H.combine2 10 (H.bool b)
| App_fun (f, l) -> H.combine3 20 (Const.hash f) (H.list Node.hash l)
| App_ho (f, a) -> H.combine3 30 (Node.hash f) (Node.hash a)
| Eq (a, b) -> H.combine3 40 (Node.hash a) (Node.hash b)
| Opaque u -> H.combine2 50 (Node.hash u)
| If (a, b, c) -> H.combine4 60 (Node.hash a) (Node.hash b) (Node.hash c)
| Not u -> H.combine2 70 (Node.hash u)
let pp out = function
| Bool b -> Fmt.bool out b
| App_fun (f, []) -> Const.pp out f
| App_fun (f, l) ->
Fmt.fprintf out "(@[%a@ %a@])" Const.pp f (Util.pp_list Node.pp) l
| App_ho (f, a) -> Fmt.fprintf out "(@[%a@ %a@])" Node.pp f Node.pp a
| Opaque t -> Node.pp out t
| Not u -> Fmt.fprintf out "(@[not@ %a@])" Node.pp u
| Eq (a, b) -> Fmt.fprintf out "(@[=@ %a@ %a@])" Node.pp a Node.pp b
| If (a, b, c) ->
Fmt.fprintf out "(@[ite@ %a@ %a@ %a@])" Node.pp a Node.pp b Node.pp c
end
module Sig_tbl = CCHashtbl.Make (Signature)
type t = {
mutable ok: bool; (* unsat? *)
tbl: node T_tbl.t;
sig_tbl: node Sig_tbl.t;
mutable combine: (node * node) list;
mutable pending: node list; (* refresh signature *)
true_: node;
false_: node;
}
let create tst : t =
let true_ = Term.true_ tst in
let false_ = Term.false_ tst in
let self =
{
ok = true;
tbl = T_tbl.create 128;
sig_tbl = Sig_tbl.create 128;
combine = [];
pending = [];
true_ = Node.make true_;
false_ = Node.make false_;
}
in
T_tbl.add self.tbl true_ self.true_;
T_tbl.add self.tbl false_ self.false_;
self
let clear (self : t) : unit =
let { ok = _; tbl; sig_tbl; pending = _; combine = _; true_; false_ } =
self
in
self.ok <- true;
self.pending <- [];
self.combine <- [];
T_tbl.clear tbl;
Sig_tbl.clear sig_tbl;
T_tbl.add tbl true_.n_t true_;
T_tbl.add tbl false_.n_t false_;
()
let sub_ t k : unit =
match A.view_as_cc t with
| Bool _ | Opaque _ -> ()
| App_fun (_, args) -> args k
| App_ho (f, a) ->
k f;
k a
| Eq (a, b) ->
k a;
k b
| Not u -> k u
| If (a, b, c) ->
k a;
k b;
k c
let rec add_t (self : t) (t : Term.t) : node =
match T_tbl.find self.tbl t with
| n -> n
| exception Not_found ->
let node = Node.make t in
T_tbl.add self.tbl t node;
(* add sub-terms, and add [t] to their parent list *)
sub_ t (fun u ->
let n_u = Node.root @@ add_t self u in
Node.add_parent n_u ~p:node);
(* need to compute signature *)
self.pending <- node :: self.pending;
node
let find_t_ (self : t) (t : Term.t) : node =
try T_tbl.find self.tbl t |> Node.root
with Not_found ->
Error.errorf "mini-cc.find_t: no node for %a" T.pp_debug t
exception E_unsat
let compute_sig (self : t) (n : node) : Signature.t option =
let[@inline] return x = Some x in
match A.view_as_cc n.n_t with
| Bool _ | Opaque _ -> None
| Eq (a, b) ->
let a = find_t_ self a in
let b = find_t_ self b in
return @@ Eq (a, b)
| Not u -> return @@ Not (find_t_ self u)
| App_fun (f, args) ->
let args = args |> Iter.map (find_t_ self) |> Iter.to_list in
if args <> [] then
return @@ App_fun (f, args)
else
None
| App_ho (f, a) ->
let f = find_t_ self f in
let a = find_t_ self a in
return @@ App_ho (f, a)
| If (a, b, c) ->
return @@ If (find_t_ self a, find_t_ self b, find_t_ self c)
let update_sig_ (self : t) (n : node) : unit =
match compute_sig self n with
| None -> ()
| Some (Eq (a, b)) ->
if Node.equal a b then (
(* reduce to [true] *)
let n2 = self.true_ in
Log.debugf 5 (fun k ->
k "(@[mini-cc.congruence-by-eq@ %a@ %a@])" Node.pp n Node.pp n2);
self.combine <- (n, n2) :: self.combine
)
| Some (Not u) when Node.equal u self.true_ ->
self.combine <- (n, self.false_) :: self.combine
| Some (Not u) when Node.equal u self.false_ ->
self.combine <- (n, self.true_) :: self.combine
| Some (If (a, b, _)) when Node.equal a self.true_ ->
self.combine <- (n, b) :: self.combine
| Some (If (a, _, c)) when Node.equal a self.false_ ->
self.combine <- (n, c) :: self.combine
| Some s ->
Log.debugf 5 (fun k -> k "(@[mini-cc.update-sig@ %a@])" Signature.pp s);
(match Sig_tbl.find self.sig_tbl s with
| n2 when Node.equal n n2 -> ()
| n2 ->
(* collision, merge *)
Log.debugf 5 (fun k ->
k "(@[mini-cc.congruence-by-sig@ %a@ %a@])" Node.pp n Node.pp n2);
self.combine <- (n, n2) :: self.combine
| exception Not_found -> Sig_tbl.add self.sig_tbl s n)
let[@inline] is_bool self n =
Node.equal self.true_ n || Node.equal self.false_ n
(* merge the two classes *)
let merge_ self n1 n2 : unit =
let n1 = Node.root n1 in
let n2 = Node.root n2 in
if not @@ Node.equal n1 n2 then (
(* merge into largest class, or into a boolean *)
let n1, n2 =
if is_bool self n1 then
n1, n2
else if is_bool self n2 then
n2, n1
else if Node.size n1 > Node.size n2 then
n1, n2
else
n2, n1
in
Log.debugf 5 (fun k ->
k "(@[mini-cc.merge@ :into %a@ %a@])" Node.pp n1 Node.pp n2);
if is_bool self n1 && is_bool self n2 then (
Log.debugf 5 (fun k -> k "(mini-cc.conflict.merge-true-false)");
self.ok <- false;
raise E_unsat
);
self.pending <- List.rev_append n2.n_parents self.pending;
(* will change signature *)
(* merge parent lists *)
n1.n_parents <- List.rev_append n2.n_parents n1.n_parents;
n1.n_size <- n2.n_size + n1.n_size;
(* update root pointer in [n2.class] *)
Node.iter_cls n2 (fun n -> n.n_root <- n1);
(* merge classes [next] pointers *)
let n1_next = n1.n_next in
n1.n_next <- n2.n_next;
n2.n_next <- n1_next
)
let[@inline] check_ok_ self = if not self.ok then raise_notrace E_unsat
(* fixpoint of the congruence closure *)
let fixpoint (self : t) : unit =
while not (CCList.is_empty self.pending && CCList.is_empty self.combine) do
check_ok_ self;
while not @@ CCList.is_empty self.pending do
let n = List.hd self.pending in
self.pending <- List.tl self.pending;
update_sig_ self n
done;
while not @@ CCList.is_empty self.combine do
let n1, n2 = List.hd self.combine in
self.combine <- List.tl self.combine;
merge_ self n1 n2
done
done
(* API *)
let add_lit (self : t) (p : T.t) (sign : bool) : unit =
match A.view_as_cc p with
| Eq (t1, t2) when sign ->
let n1 = add_t self t1 in
let n2 = add_t self t2 in
self.combine <- (n1, n2) :: self.combine
| _ ->
(* just merge with true/false *)
let n = add_t self p in
let n2 =
if sign then
self.true_
else
self.false_
in
self.combine <- (n, n2) :: self.combine
let check_sat (self : t) : bool =
try
fixpoint self;
true
with E_unsat ->
self.ok <- false;
false
let classes self : _ Iter.t =
T_tbl.values self.tbl |> Iter.filter Node.is_root
|> Iter.map (fun n -> Node.iter_cls n |> Iter.map Node.term)
end

View file

@ -1,44 +0,0 @@
(** Mini congruence closure
This implementation is as simple as possible, and doesn't provide
backtracking, theories, or explanations.
It just decides the satisfiability of a set of (dis)equations.
*)
open Sidekick_core
module CC_view = Sidekick_cc.View
(** Argument for the functor {!Make}
It only requires a Term.t structure, and a congruence-oriented view. *)
module type ARG = sig
val view_as_cc : Term.t -> (Const.t, Term.t, Term.t Iter.t) CC_view.t
end
(** Main signature for an instance of the mini congruence closure *)
module type S = sig
type t
(** An instance of the congruence closure. Mutable *)
val create : Term.store -> t
(** New instance *)
val clear : t -> unit
(** Fully reset the congruence closure's state *)
val add_lit : t -> Term.t -> bool -> unit
(** [add_lit cc p sign] asserts that [p] is true if [sign],
or [p] is false if [not sign]. If [p] is an equation and [sign]
is [true], this adds a new equation to the congruence relation. *)
val check_sat : t -> bool
(** [check_sat cc] returns [true] if the current state is satisfiable, [false]
if it's unsatisfiable. *)
val classes : t -> Term.t Iter.t Iter.t
(** Traverse the set of classes in the congruence closure.
This should be called only if {!check} returned [Sat]. *)
end
(** Instantiate the congruence closure for the given Term.t structure. *)
module Make (_ : ARG) : S

View file

@ -1,5 +0,0 @@
(library
(name Sidekick_mini_cc)
(public_name sidekick.mini-cc)
(libraries containers iter sidekick.cc sidekick.core sidekick.util)
(flags :standard -warn-error -a+8 -w -32 -open Sidekick_util))

View file

@ -1,4 +0,0 @@
(library
(name sidekick_test_minicc)
(libraries sidekick.mini-cc sidekick-base alcotest)
(flags :standard -warn-error -a+8))

View file

@ -1,179 +0,0 @@
open! Sidekick_base
module A = Alcotest
module CC = Sidekick_mini_cc.Make (struct
module T = Sidekick_base.Solver_arg
let view_as_cc = Term.cc_view
end)
module Setup () = struct
let tst = Term.create ()
let ( @-> ) l ret = Ty.Fun.mk l ret
let ty_i = Ty.atomic_uninterpreted (ID.make "$i")
let ty_bool = Ty.bool ()
let fun_f = Fun.mk_undef (ID.make "f") ([ ty_i ] @-> ty_i)
let fun_g = Fun.mk_undef (ID.make "g") ([ ty_i; ty_i ] @-> ty_i)
let fun_p = Fun.mk_undef (ID.make "p") ([ ty_i ] @-> ty_bool)
let fun_a = Fun.mk_undef_const (ID.make "a") ty_i
let fun_b = Fun.mk_undef_const (ID.make "b") ty_i
let fun_c = Fun.mk_undef_const (ID.make "c") ty_i
let fun_d1 = Fun.mk_undef_const (ID.make "d1") ty_i
let fun_d2 = Fun.mk_undef_const (ID.make "d2") ty_i
let true_ = Term.true_ tst
let false_ = Term.false_ tst
let const c = Term.const tst c
let app_a f l = Term.app_fun tst f l
let app_l f l = Term.app_fun tst f (CCArray.of_list l)
let not_ x = Term.not_ tst x
let eq a b = Term.eq tst a b
let neq a b = Term.not_ tst (eq a b)
let ite a b c = Term.ite tst a b c
let a = const fun_a
let b = const fun_b
let c = const fun_c
let d1 = const fun_d1
let d2 = const fun_d2
let f t1 = app_l fun_f [ t1 ]
let g t1 t2 = app_l fun_g [ t1; t2 ]
let p t1 = app_l fun_p [ t1 ]
end
let l : unit Alcotest.test_case list ref = ref []
let mk_test name f = l := (name, `Quick, f) :: !l
let () =
mk_test "test_p_a_b" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.(p a) true;
CC.add_lit cc S.(p b) false;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.(eq a b) true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
()
let () =
mk_test "test_p_a_b_2" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.(p a) true;
CC.add_lit cc S.(not_ @@ p b) true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.(eq a b) true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
()
let () =
mk_test "test_f_f_f_a" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.(neq a (f (f (f (f (f (f a))))))) true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.(eq a (f a)) true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
()
let () =
mk_test "test_repeated_f_f_f_a" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
for _i = 0 to 10 do
CC.add_lit cc S.(neq a (f (f (f (f (f (f a))))))) true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.(eq a (f a)) true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
CC.clear cc
done;
()
let () =
mk_test "test_trans" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.(eq a b) true;
CC.add_lit cc S.(eq b c) true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.(neq (f a) (f c)) true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
()
let () =
mk_test "test_true" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.true_ true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.false_ true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
()
let () =
mk_test "test_repeated_true" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
for _i = 0 to 10 do
CC.add_lit cc S.true_ true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.false_ true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
CC.clear cc
done;
()
let () =
mk_test "test_false" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.false_ true;
A.(check bool) "is-unsat" (CC.check_sat cc) false;
()
let () =
mk_test "test_not_false" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.(not_ false_) true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
()
let () =
mk_test "test_ite" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
for _i = 0 to 10 do
CC.add_lit cc S.(eq a b) true;
CC.add_lit cc S.(p (ite (eq a c) d1 d2)) true;
CC.add_lit cc S.(not_ (p d1)) true;
CC.add_lit cc S.(p d2) true;
A.(check bool) "is-sat" (CC.check_sat cc) true;
CC.add_lit cc S.(eq b c) true;
(* force (p d1) *)
A.(check bool) "is-unsat" (CC.check_sat cc) false;
CC.clear cc
done;
()
(* from the following PO:
`cl (- a = (g a c)),
(- b = (g a c)),
(- c = (g c b)),
(- a = (g c c)),
(- (g c (g c b)) = (g (g c c) b)),
(+ (g a b) = (g a c))))`
*)
let () =
mk_test "test_reg_1" @@ fun () ->
let module S = Setup () in
let cc = CC.create S.tst in
CC.add_lit cc S.(eq a (g a c)) true;
CC.add_lit cc S.(eq b (g a c)) true;
CC.add_lit cc S.(eq c (g c b)) true;
CC.add_lit cc S.(eq a (g c c)) true;
CC.add_lit cc S.(eq (g c (g c b)) (g (g c c) b)) true;
CC.add_lit cc S.(eq (g a b) (g a c)) false;
(* goal *)
A.(check bool) "is-unsat" (CC.check_sat cc) false;
()
let tests = "mini-cc", List.rev !l

View file

@ -1,13 +1,13 @@
(** A signature is a shallow term shape where immediate subterms (** A signature is a shallow term shape where immediate subterms
are representative *) are representative *)
open View open Sidekick_core.CC_view
open Types_ open Types_
type t = signature type t = signature
let equal (s1 : t) s2 : bool = let equal (s1 : t) s2 : bool =
let open View in let open CC_view in
match s1, s2 with match s1, s2 with
| Bool b1, Bool b2 -> b1 = b2 | Bool b1, Bool b2 -> b1 = b2
| App_fun (f1, []), App_fun (f2, []) -> Const.equal f1 f2 | App_fun (f1, []), App_fun (f2, []) -> Const.equal f1 f2

View file

@ -18,7 +18,7 @@ type e_node = {
An equivalence class is represented by its "root" element, An equivalence class is represented by its "root" element,
the representative. *) the representative. *)
and signature = (Const.t, e_node, e_node list) View.t and signature = (Const.t, e_node, e_node list) CC_view.t
and explanation_forest_link = and explanation_forest_link =
| FL_none | FL_none

View file

@ -1,38 +0,0 @@
type ('f, 't, 'ts) t =
| Bool of bool
| App_fun of 'f * 'ts
| App_ho of 't * 't
| If of 't * 't * 't
| Eq of 't * 't
| Not of 't
| Opaque of 't
(* do not enter *)
let map_view ~f_f ~f_t ~f_ts (v : _ t) : _ t =
match v with
| Bool b -> Bool b
| App_fun (f, args) -> App_fun (f_f f, f_ts args)
| App_ho (f, a) -> App_ho (f_t f, f_t a)
| Not t -> Not (f_t t)
| If (a, b, c) -> If (f_t a, f_t b, f_t c)
| Eq (a, b) -> Eq (f_t a, f_t b)
| Opaque t -> Opaque (f_t t)
let iter_view ~f_f ~f_t ~f_ts (v : _ t) : unit =
match v with
| Bool _ -> ()
| App_fun (f, args) ->
f_f f;
f_ts args
| App_ho (f, a) ->
f_t f;
f_t a
| Not t -> f_t t
| If (a, b, c) ->
f_t a;
f_t b;
f_t c
| Eq (a, b) ->
f_t a;
f_t b
| Opaque t -> f_t t

View file

@ -1,33 +0,0 @@
(** View terms through the lens of the Congruence Closure *)
(** A view of a term fron the point of view of the congruence closure.
- ['f] is the type of function symbols
- ['t] is the type of terms
- ['ts] is the type of sequences of terms (arguments of function application)
*)
type ('f, 't, 'ts) t =
| Bool of bool
| App_fun of 'f * 'ts
| App_ho of 't * 't
| If of 't * 't * 't
| Eq of 't * 't
| Not of 't
| Opaque of 't (** do not enter *)
val map_view :
f_f:('a -> 'b) ->
f_t:('c -> 'd) ->
f_ts:('e -> 'f) ->
('a, 'c, 'e) t ->
('b, 'd, 'f) t
(** Map function over a view, one level deep.
Each function maps over a different type, e.g. [f_t] maps over terms *)
val iter_view :
f_f:('a -> unit) ->
f_t:('b -> unit) ->
f_ts:('c -> unit) ->
('a, 'b, 'c) t ->
unit
(** Iterate over a view, one level deep. *)