feat: modular statistics aggregate

This commit is contained in:
Simon Cruanes 2019-03-22 20:14:28 -05:00
parent fadf76d944
commit 539186bfe6
11 changed files with 121 additions and 48 deletions

View file

@ -334,6 +334,9 @@ module Make(A: ARG) = struct
(* pairs to explain *) (* pairs to explain *)
true_ : node lazy_t; true_ : node lazy_t;
false_ : node lazy_t; false_ : node lazy_t;
stat: Stat.t;
count_conflict: int Stat.counter;
count_merge: int Stat.counter;
} }
(* TODO: an additional union-find to keep track, for each term, (* TODO: an additional union-find to keep track, for each term,
of the terms they are known to be equal to, according of the terms they are known to be equal to, according
@ -459,6 +462,7 @@ module Make(A: ARG) = struct
Vec.clear cc.pending; Vec.clear cc.pending;
Vec.clear cc.combine; Vec.clear cc.combine;
let c = List.rev_map A.Lit.neg e in let c = List.rev_map A.Lit.neg e in
Stat.incr cc.count_conflict;
acts.Msat.acts_raise_conflict c A.Proof.default acts.Msat.acts_raise_conflict c A.Proof.default
let[@inline] all_classes cc : repr Iter.t = let[@inline] all_classes cc : repr Iter.t =
@ -717,6 +721,7 @@ module Make(A: ARG) = struct
if not @@ N.equal ra rb then ( if not @@ N.equal ra rb then (
assert (N.is_root ra); assert (N.is_root ra);
assert (N.is_root rb); assert (N.is_root rb);
Stat.incr cc.count_merge;
(* check we're not merging [true] and [false] *) (* check we're not merging [true] and [false] *)
if (N.equal ra (true_ cc) && N.equal rb (false_ cc)) || if (N.equal ra (true_ cc) && N.equal rb (false_ cc)) ||
(N.equal rb (true_ cc) && N.equal ra (false_ cc)) then ( (N.equal rb (true_ cc) && N.equal ra (false_ cc)) then (
@ -1005,7 +1010,8 @@ module Make(A: ARG) = struct
let on_merge cc f = cc.on_merge <- f :: cc.on_merge let on_merge cc f = cc.on_merge <- f :: cc.on_merge
let create ?th:(theories=[]) ?(on_merge=[]) ?(size=`Big) (tst:term_state) : t = let create ?(stat=Stat.global)
?th:(theories=[]) ?(on_merge=[]) ?(size=`Big) (tst:term_state) : t =
let size = match size with `Small -> 128 | `Big -> 2048 in let size = match size with `Small -> 128 | `Big -> 2048 in
let rec cc = { let rec cc = {
tst; tst;
@ -1020,6 +1026,9 @@ module Make(A: ARG) = struct
ps_queue=Vec.create(); ps_queue=Vec.create();
true_; true_;
false_; false_;
stat;
count_conflict=Stat.mk_int stat "cc.conflicts";
count_merge=Stat.mk_int stat "cc.merges";
} and true_ = lazy ( } and true_ = lazy (
add_term cc (T.bool tst true) add_term cc (T.bool tst true)
) and false_ = lazy ( ) and false_ = lazy (

View file

@ -151,6 +151,7 @@ module type S = sig
end end
val create : val create :
?stat:Stat.t ->
?th:Theory.t list -> ?th:Theory.t list ->
?on_merge:(t -> N.t -> N.t -> Expl.t -> unit) list -> ?on_merge:(t -> N.t -> N.t -> Expl.t -> unit) list ->
?size:[`Small | `Big] -> ?size:[`Small | `Big] ->

View file

@ -152,7 +152,7 @@ let main () =
E.return() E.return()
in in
if !p_stat then ( if !p_stat then (
Format.printf "%a@." Sidekick_smt.Solver.pp_stats solver; Format.printf "%a@." Solver.pp_stats solver;
); );
if !p_gc_stat then ( if !p_gc_stat then (
Printf.printf "(gc_stats\n%t)\n" Gc.print_stat; Printf.printf "(gc_stats\n%t)\n" Gc.print_stat;

View file

@ -23,6 +23,8 @@ module Proof = Sat_solver.Proof
type t = { type t = {
solver: Sat_solver.t; solver: Sat_solver.t;
stat: Stat.t; stat: Stat.t;
count_clause: int Stat.counter;
count_solve: int Stat.counter;
config: Config.t config: Config.t
} }
@ -35,14 +37,16 @@ let[@inline] tst self = Theory_combine.tst (th_combine self)
let[@inline] mk_atom_lit self lit : Atom.t = Sat_solver.make_atom self.solver lit let[@inline] mk_atom_lit self lit : Atom.t = Sat_solver.make_atom self.solver lit
let[@inline] mk_atom_t self ?sign t : Atom.t = let[@inline] mk_atom_t self ?sign t : Atom.t =
let lit = Lit.atom (tst self) ?sign t in let lit = Lit.atom (tst self) ?sign t in
mk_atom_lit self lit mk_atom_lit self lit
let create ?size ?(config=Config.empty) ?store_proof ~theories () : t = let create ?(stat=Stat.global) ?size ?(config=Config.empty) ?store_proof ~theories () : t =
let th_combine = Theory_combine.create() in let th_combine = Theory_combine.create ~stat () in
let self = { let self = {
solver=Sat_solver.create ?store_proof ?size th_combine; solver=Sat_solver.create ?store_proof ?size th_combine;
stat=Stat.create (); stat;
count_clause=Stat.mk_int stat "input-clauses";
count_solve=Stat.mk_int stat "solve";
config; config;
} in } in
(* now add the theories *) (* now add the theories *)
@ -54,17 +58,6 @@ let create ?size ?(config=Config.empty) ?store_proof ~theories () : t =
] Proof_default; ] Proof_default;
self self
(** {2 Sat Solver} *)
let print_progress (st:t) : unit =
Printf.printf "\r[%.2f] clauses %d | lemmas %d%!"
(get_time())
st.stat.Stat.num_clause_push
st.stat.Stat.num_clause_tautology
let flush_progress (): unit =
Printf.printf "\r%-80d\r%!" 0
(** {2 Toplevel Goals} (** {2 Toplevel Goals}
List of toplevel goals to satisfy. Mainly used for checking purpose List of toplevel goals to satisfy. Mainly used for checking purpose
@ -155,16 +148,8 @@ let clauses_of_unsat_core (core:Sat_solver.clause list): Lit.t IArray.t Iter.t =
let pp_term_graph _out (_:t) = let pp_term_graph _out (_:t) =
() ()
let pp_stats out (s:t) : unit = let pp_stats out (self:t) : unit =
Format.fprintf out Stat.pp_all out (Stat.all @@ stats self)
"(@[<hv1>stats@ \
:num_clause_push %d@ \
:num_clause_tautology %d@ \
:num_propagations %d@ \
@])"
s.stat.Stat.num_clause_push
s.stat.Stat.num_clause_tautology
s.stat.Stat.num_propagations
let do_on_exit ~on_exit = let do_on_exit ~on_exit =
List.iter (fun f->f()) on_exit; List.iter (fun f->f()) on_exit;
@ -187,6 +172,7 @@ let assume (self:t) (c:Lit.t IArray.t) : unit =
let sat = solver self in let sat = solver self in
IArray.iter (fun lit -> add_bool_subterms_ self @@ Lit.term lit) c; IArray.iter (fun lit -> add_bool_subterms_ self @@ Lit.term lit) c;
let c = IArray.to_array_map (Sat_solver.make_atom sat) c in let c = IArray.to_array_map (Sat_solver.make_atom sat) c in
Stat.incr self.count_clause;
Sat_solver.add_clause_a sat c Proof_default Sat_solver.add_clause_a sat c Proof_default
(* TODO: remove? use a special constant + micro theory instead? (* TODO: remove? use a special constant + micro theory instead?
@ -205,6 +191,7 @@ let check_model (_s:t) : unit =
(not the value depth limit) *) (not the value depth limit) *)
let solve ?(on_exit=[]) ?(check=true) ~assumptions (self:t) : res = let solve ?(on_exit=[]) ?(check=true) ~assumptions (self:t) : res =
let r = Sat_solver.solve ~assumptions (solver self) in let r = Sat_solver.solve ~assumptions (solver self) in
Stat.incr self.count_solve;
match r with match r with
| Sat_solver.Sat st -> | Sat_solver.Sat st ->
Log.debugf 1 (fun k->k "SAT"); Log.debugf 1 (fun k->k "SAT");

View file

@ -37,6 +37,7 @@ type t
(** Solver state *) (** Solver state *)
val create : val create :
?stat:Stat.t ->
?size:[`Big | `Tiny | `Small] -> ?size:[`Big | `Tiny | `Small] ->
?config:Config.t -> ?config:Config.t ->
?store_proof:bool -> ?store_proof:bool ->

View file

@ -1,12 +0,0 @@
type t = {
mutable num_clause_push : int;
mutable num_clause_tautology : int;
mutable num_propagations : int;
}
let create () : t = {
num_clause_push = 0;
num_clause_tautology = 0;
num_propagations = 0;
}

View file

@ -23,12 +23,13 @@ type theory_state =
(* TODO: first-class module instead *) (* TODO: first-class module instead *)
type t = { type t = {
tst: Term.state; tst: Term.state; (** state for managing terms *)
(** state for managing terms *) cc: CC.t lazy_t; (** congruence closure *)
cc: CC.t lazy_t; stat: Stat.t;
(** congruence closure *) count_axiom: int Stat.counter;
mutable theories : theory_state list; count_conflict: int Stat.counter;
(** Set of theories *) count_propagate: int Stat.counter;
mutable theories : theory_state list; (** Set of theories *)
} }
let[@inline] cc (t:t) = Lazy.force t.cc let[@inline] cc (t:t) = Lazy.force t.cc
@ -52,13 +53,18 @@ let assert_lits_ ~final (self:t) acts (lits:Lit.t Iter.t) : unit =
CC.check cc acts; CC.check cc acts;
let module A = struct let module A = struct
let cc = cc let cc = cc
let[@inline] raise_conflict c : 'a = acts.Msat.acts_raise_conflict c Proof_default let[@inline] raise_conflict c : 'a =
Stat.incr self.count_conflict;
acts.Msat.acts_raise_conflict c Proof_default
let[@inline] propagate p cs : unit = let[@inline] propagate p cs : unit =
Stat.incr self.count_propagate;
acts.Msat.acts_propagate p (Msat.Consequence (fun () -> cs(), Proof_default)) acts.Msat.acts_propagate p (Msat.Consequence (fun () -> cs(), Proof_default))
let[@inline] propagate_l p cs : unit = propagate p (fun()->cs) let[@inline] propagate_l p cs : unit = propagate p (fun()->cs)
let[@inline] add_local_axiom lits : unit = let[@inline] add_local_axiom lits : unit =
Stat.incr self.count_axiom;
acts.Msat.acts_add_clause ~keep:false lits Proof_default acts.Msat.acts_add_clause ~keep:false lits Proof_default
let[@inline] add_persistent_axiom lits : unit = let[@inline] add_persistent_axiom lits : unit =
Stat.incr self.count_axiom;
acts.Msat.acts_add_clause ~keep:true lits Proof_default acts.Msat.acts_add_clause ~keep:true lits Proof_default
let[@inline] add_lit lit : unit = acts.Msat.acts_mk_lit lit let[@inline] add_lit lit : unit = acts.Msat.acts_mk_lit lit
end in end in
@ -120,7 +126,7 @@ let mk_model (self:t) lits : Model.t =
(** {2 Main} *) (** {2 Main} *)
(* create a new theory combination *) (* create a new theory combination *)
let create () : t = let create ?(stat=Stat.global) () : t =
Log.debug 5 "th_combine.create"; Log.debug 5 "th_combine.create";
let rec self = { let rec self = {
tst=Term.create ~size:1024 (); tst=Term.create ~size:1024 ();
@ -130,6 +136,10 @@ let create () : t =
CC.create ~size:`Big self.tst; CC.create ~size:`Big self.tst;
); );
theories = []; theories = [];
stat;
count_axiom = Stat.mk_int stat "th-axioms";
count_propagate = Stat.mk_int stat "th-propagations";
count_conflict = Stat.mk_int stat "th-conflicts";
} in } in
ignore (Lazy.force @@ self.cc : CC.t); ignore (Lazy.force @@ self.cc : CC.t);
self self

View file

@ -11,7 +11,7 @@ include Msat.Solver_intf.PLUGIN_CDCL_T
with module Formula = Lit with module Formula = Lit
and type proof = Proof.t and type proof = Proof.t
val create : unit -> t val create : ?stat:Stat.t -> unit -> t
val cc : t -> CC.t val cc : t -> CC.t
val tst : t -> Term.state val tst : t -> Term.state

View file

@ -10,3 +10,4 @@ module Error = Error
module IArray = IArray module IArray = IArray
module Intf = Intf module Intf = Intf
module Bag = Bag module Bag = Bag
module Stat = Stat

50
src/util/Stat.ml Normal file
View file

@ -0,0 +1,50 @@
(** {1 Statistics} *)
module Fmt = CCFormat
module S_map = CCMap.Make(String)
type 'a counter = {
name: string;
mutable count: 'a;
}
type ex_counter =
| C_int : int counter -> ex_counter
| C_float : float counter -> ex_counter
type t = {
mutable cs: ex_counter S_map.t;
}
let create() : t = {cs=S_map.empty}
let register_ self name c = self.cs <- S_map.add name c self.cs
let all (self:t) = S_map.values self.cs
let mk_int self name =
match S_map.find name self.cs with
| C_int s -> s
| _ -> Error.errorf "incompatible types for stat %S" name
| exception Not_found ->
let c = {name; count=0} in
register_ self name (C_int c); c
let mk_float self name =
match S_map.find name self.cs with
| C_float s -> s
| _ -> Error.errorf "incompatible types for stat %S" name
| exception Not_found ->
let c = {name; count=0.} in
register_ self name (C_float c); c
let[@inline] incr x = x.count <- 1 + x.count
let[@inline] incr_f x by = x.count <- by +. x.count
let pp_all out l =
let pp_w out = function
| C_int {name; count} -> Fmt.fprintf out "@[:%s %d@]" name count
| C_float {name; count} -> Fmt.fprintf out "@[:%s %.4f@]" name count
in
Fmt.fprintf out "(@[stats@ %a@])" Fmt.(seq ~sep:(return "@ ") pp_w) l
let global = create()

26
src/util/Stat.mli Normal file
View file

@ -0,0 +1,26 @@
(** {1 Statistics} *)
module Fmt = CCFormat
type t
val create : unit -> t
type 'a counter
val mk_int : t -> string -> int counter
val mk_float : t -> string -> float counter
val incr : int counter -> unit
val incr_f : float counter -> float -> unit
(** Existential counter *)
type ex_counter
val all : t -> ex_counter Iter.t
val pp_all : ex_counter Iter.t Fmt.printer
val global : t
(** Global statistics, by default *)