mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-06 03:05:31 -05:00
220 lines
6.5 KiB
OCaml
220 lines
6.5 KiB
OCaml
|
|
module type ARG = CC_types.FULL
|
|
|
|
module type THEORY_KEY = sig
|
|
type ('term,'lit,'a) t
|
|
(** An access key for theories which have per-class data ['a] *)
|
|
|
|
val create :
|
|
?pp:'a Fmt.printer ->
|
|
name:string ->
|
|
eq:('a -> 'a -> bool) ->
|
|
merge:('a -> 'a -> 'a) ->
|
|
unit ->
|
|
('term,'lit,'a) t
|
|
(** Generative creation of keys for the given theory data.
|
|
|
|
@param eq : Equality. This is used to optimize backtracking info.
|
|
|
|
@param merge :
|
|
[merge d1 d2] is called when merging classes with data [d1] and [d2]
|
|
respectively. The theory should already have checked that the merge
|
|
is compatible, and this produces the combined data for terms in the
|
|
merged class.
|
|
@param name name of the theory which owns this data
|
|
@param pp a printer for the data
|
|
*)
|
|
|
|
val equal : ('t,'lit,_) t -> ('t,'lit,_) t -> bool
|
|
(** Checks if two keys are equal (generatively) *)
|
|
|
|
val pp : _ t Fmt.printer
|
|
(** Prints the name of the key. *)
|
|
end
|
|
|
|
module type S = sig
|
|
type term_state
|
|
type term
|
|
type fun_
|
|
type lit
|
|
type proof
|
|
type model
|
|
|
|
(** Implementation of theory keys *)
|
|
module Key : THEORY_KEY
|
|
|
|
type t
|
|
(** Global state of the congruence closure *)
|
|
|
|
(** An equivalence class is a set of terms that are currently equal
|
|
in the partial model built by the solver.
|
|
The class is represented by a collection of nodes, one of which is
|
|
distinguished and is called the "representative".
|
|
|
|
All information pertaining to the whole equivalence class is stored
|
|
in this representative's node.
|
|
|
|
When two classes become equal (are "merged"), one of the two
|
|
representatives is picked as the representative of the new class.
|
|
The new class contains the union of the two old classes' nodes.
|
|
|
|
We also allow theories to store additional information in the
|
|
representative. This information can be used when two classes are
|
|
merged, to detect conflicts and solve equations à la Shostak.
|
|
*)
|
|
module N : sig
|
|
type t
|
|
|
|
val term : t -> term
|
|
val equal : t -> t -> bool
|
|
val hash : t -> int
|
|
val pp : t Fmt.printer
|
|
|
|
val is_root : t -> bool
|
|
(** Is the node a root (ie the representative of its class)? *)
|
|
|
|
val iter_class : t -> t Iter.t
|
|
(** Traverse the congruence class.
|
|
Invariant: [is_root n] (see {!find} below) *)
|
|
|
|
val iter_parents : t -> t Iter.t
|
|
(** Traverse the parents of the class.
|
|
Invariant: [is_root n] (see {!find} below) *)
|
|
end
|
|
|
|
module Expl : sig
|
|
type t
|
|
val pp : t Fmt.printer
|
|
|
|
val mk_merge : N.t -> N.t -> t
|
|
val mk_lit : lit -> t
|
|
val mk_list : t list -> t
|
|
end
|
|
|
|
type node = N.t
|
|
(** A node of the congruence closure *)
|
|
|
|
type repr = N.t
|
|
(** Node that is currently a representative *)
|
|
|
|
type explanation = Expl.t
|
|
|
|
type conflict = lit list
|
|
|
|
(** Accessors *)
|
|
|
|
val term_state : t -> term_state
|
|
|
|
val find : t -> node -> repr
|
|
(** Current representative *)
|
|
|
|
val add_term : t -> term -> node
|
|
(** Add the term to the congruence closure, if not present already.
|
|
Will be backtracked. *)
|
|
|
|
(** Actions available to the theory *)
|
|
type sat_actions = (Msat.void, lit, Msat.void, proof) Msat.acts
|
|
|
|
module Theory : sig
|
|
type cc = t
|
|
type t
|
|
|
|
type 'a key = (term,lit,'a) Key.t
|
|
|
|
val raise_conflict : cc -> Expl.t -> unit
|
|
(** Raise a conflict with the given explanation
|
|
it must be a theory tautology that [expl ==> absurd].
|
|
To be used in theories. *)
|
|
|
|
val merge : cc -> N.t -> N.t -> Expl.t -> unit
|
|
(** Merge these two nodes given this explanation.
|
|
It must be a theory tautology that [expl ==> n1 = n2].
|
|
To be used in theories. *)
|
|
|
|
val add_term : cc -> term -> N.t
|
|
(** Add/retrieve node for this term.
|
|
To be used in theories *)
|
|
|
|
val get_data : cc -> N.t -> 'a key -> 'a option
|
|
(** Get data information for this particular representative *)
|
|
|
|
val add_data : cc -> N.t -> 'a key -> 'a -> unit
|
|
(** Add data to this particular representative. Will be backtracked. *)
|
|
|
|
val make :
|
|
key:'a key ->
|
|
on_merge:(cc -> N.t -> 'a -> N.t -> 'a -> Expl.t -> unit) ->
|
|
on_new_term:(cc -> N.t -> term -> 'a option) ->
|
|
unit ->
|
|
t
|
|
(** Build a micro theory. It can use the callbacks above. *)
|
|
end
|
|
|
|
val create :
|
|
?th:Theory.t list ->
|
|
?on_merge:(t -> N.t -> N.t -> Expl.t -> unit) list ->
|
|
?size:[`Small | `Big] ->
|
|
term_state ->
|
|
t
|
|
(** Create a new congruence closure. *)
|
|
|
|
val add_th : t -> Theory.t -> unit
|
|
(** Add a (micro) theory to the congruence closure.
|
|
@raise Error.Error if there is already a theory with
|
|
the same key. *)
|
|
|
|
val on_merge : t -> (t -> N.t -> N.t -> Expl.t -> unit) -> unit
|
|
(** Add a function to be called when two classes are merged *)
|
|
|
|
val set_as_lit : t -> N.t -> lit -> unit
|
|
(** map the given node to a literal. *)
|
|
|
|
val find_t : t -> term -> repr
|
|
(** Current representative of the term.
|
|
@raise Not_found if the term is not already {!add}-ed. *)
|
|
|
|
val add_seq : t -> term Iter.t -> unit
|
|
(** Add a sequence of terms to the congruence closure *)
|
|
|
|
val all_classes : t -> repr Iter.t
|
|
(** All current classes. This is costly, only use if there is no other solution *)
|
|
|
|
val assert_lit : t -> lit -> unit
|
|
(** Given a literal, assume it in the congruence closure and propagate
|
|
its consequences. Will be backtracked.
|
|
|
|
Useful for the theory combination or the SAT solver's functor *)
|
|
|
|
val assert_lits : t -> lit Iter.t -> unit
|
|
(** Addition of many literals *)
|
|
|
|
val assert_eq : t -> term -> term -> lit list -> unit
|
|
(** merge the given terms with some explanations *)
|
|
|
|
(* TODO: remove and move into its own library as a micro theory
|
|
val assert_distinct : t -> term list -> neq:term -> lit -> unit
|
|
(** [assert_distinct l ~neq:u e] asserts all elements of [l] are distinct
|
|
because [lit] is true
|
|
precond: [u = distinct l] *)
|
|
*)
|
|
|
|
val check : t -> sat_actions -> unit
|
|
(** Perform all pending operations done via {!assert_eq}, {!assert_lit}, etc.
|
|
Will use the [sat_actions] to propagate literals, declare conflicts, etc. *)
|
|
|
|
val push_level : t -> unit
|
|
(** Push backtracking level *)
|
|
|
|
val pop_levels : t -> int -> unit
|
|
(** Restore to state [n] calls to [push_level] earlier. Used during backtracking. *)
|
|
|
|
val mk_model : t -> model -> model
|
|
(** Enrich a model by mapping terms to their representative's value,
|
|
if any. Otherwise map the representative to a fresh value *)
|
|
|
|
(**/**)
|
|
val check_invariants : t -> unit
|
|
val pp_full : t Fmt.printer
|
|
(**/**)
|
|
|
|
end
|