feat(sudoku): add stats

This commit is contained in:
Simon Cruanes 2022-08-13 13:45:38 -04:00
parent 63802fe3d6
commit 6ccabc70aa
No known key found for this signature in database
GPG key ID: EBFFF6F283F3A2B4

View file

@ -141,7 +141,7 @@ module B_ref = Sidekick_util.Backtrackable_ref
module Solver : sig module Solver : sig
type t type t
val create : Grid.t -> t val create : stat:Stat.t -> Grid.t -> t
val solve : t -> Grid.t option val solve : t -> Grid.t option
end = struct end = struct
open Sidekick_core open Sidekick_core
@ -180,15 +180,18 @@ end = struct
type t type t
val grid : t -> Grid.t val grid : t -> Grid.t
val create : Term.store -> Grid.t -> t val create : stat:Stat.t -> Term.store -> Grid.t -> t
val to_plugin : t -> Sat.plugin val to_plugin : t -> Sat.plugin
end = struct end = struct
type t = { tst: Term.store; grid: Grid.t B_ref.t } type t = {
tst: Term.store;
grid: Grid.t B_ref.t;
stat_check_full: int Stat.counter;
stat_conflict: int Stat.counter;
}
let[@inline] grid self : Grid.t = B_ref.get self.grid let[@inline] grid self : Grid.t = B_ref.get self.grid
let[@inline] set_grid self g : unit = B_ref.set self.grid g let[@inline] set_grid self g : unit = B_ref.set self.grid g
let push_level self = B_ref.push_level self.grid
let pop_levels self n = B_ref.pop_levels self.grid n
let pp_c_ = Fmt.(list ~sep:(return "@ ")) Lit.pp let pp_c_ = Fmt.(list ~sep:(return "@ ")) Lit.pp
let[@inline] logs_conflict kind c : unit = let[@inline] logs_conflict kind c : unit =
@ -200,6 +203,7 @@ end = struct
let (module A) = acts in let (module A) = acts in
Grid.all_cells (grid self) (fun (x, y, c) -> Grid.all_cells (grid self) (fun (x, y, c) ->
if Cell.is_empty c then ( if Cell.is_empty c then (
Stat.incr self.stat_check_full;
let c = let c =
CCList.init 9 (fun c -> CCList.init 9 (fun c ->
mk_cell_lit self.tst x y (Cell.make (c + 1))) mk_cell_lit self.tst x y (Cell.make (c + 1)))
@ -214,7 +218,7 @@ end = struct
Log.debugf 4 (fun k -> Log.debugf 4 (fun k ->
k "(@[sudoku.check@ @[:g %a@]@])" Grid.pp (B_ref.get self.grid)); k "(@[sudoku.check@ @[:g %a@]@])" Grid.pp (B_ref.get self.grid));
let (module A) = acts in let (module A) = acts in
let[@inline] all_diff kind f = let[@inline] all_diff c_kind f =
let pairs = let pairs =
f (grid self) f (grid self)
|> Iter.flat_map (fun set -> |> Iter.flat_map (fun set ->
@ -231,7 +235,8 @@ end = struct
mk_cell_lit self.tst ~sign:false x2 y2 c2; mk_cell_lit self.tst ~sign:false x2 y2 c2;
] ]
in in
logs_conflict ("all-diff." ^ kind) c; Stat.incr self.stat_conflict;
logs_conflict c_kind c;
A.raise_conflict c Proof_trace.dummy_step_id A.raise_conflict c Proof_trace.dummy_step_id
)) ))
in in
@ -282,12 +287,18 @@ end = struct
check_full_ self acts; check_full_ self acts;
check_ self acts check_ self acts
let create tst g : t = { tst; grid = B_ref.create g } let create ~stat tst g : t =
{
tst;
grid = B_ref.create g;
stat_check_full = Stat.mk_int stat "sudoku.check-cell-full";
stat_conflict = Stat.mk_int stat "sudoku.conflict";
}
let to_plugin (self : t) : Sat.plugin = let to_plugin (self : t) : Sat.plugin =
Sat.mk_plugin_cdcl_t Sat.mk_plugin_cdcl_t
~push_level:(fun () -> push_level self) ~push_level:(fun () -> B_ref.push_level self.grid)
~pop_levels:(fun n -> pop_levels self n) ~pop_levels:(fun n -> B_ref.pop_levels self.grid n)
~partial_check:(partial_check self) ~final_check:(final_check self) () ~partial_check:(partial_check self) ~final_check:(final_check self) ()
end end
@ -312,20 +323,20 @@ end = struct
(* TODO: print some stats *) (* TODO: print some stats *)
r r
let create g : t = let create ~stat g : t =
let tst = Term.Store.create () in let tst = Term.Store.create () in
let theory = Theory.create tst g in let theory = Theory.create ~stat tst g in
let plugin : Sat.plugin = Theory.to_plugin theory in let plugin : Sat.plugin = Theory.to_plugin theory in
{ {
tst; tst;
solver = Sat.create ~proof:Proof_trace.dummy plugin; solver = Sat.create ~stat ~proof:Proof_trace.dummy plugin;
theory; theory;
grid0 = g; grid0 = g;
} }
end end
let solve_grid (g : Grid.t) : Grid.t option = let solve_grid ~stat (g : Grid.t) : Grid.t option =
let s = Solver.create g in let s = Solver.create ~stat g in
Solver.solve s Solver.solve s
module type CHRONO = sig module type CHRONO = sig
@ -341,7 +352,7 @@ let chrono ~pp_time : (module CHRONO) =
end in end in
(module M) (module M)
let solve_file ~pp_time file = let solve_file ~use_stats ~pp_time file =
let@ () = Profile.with_ "solve-file" in let@ () = Profile.with_ "solve-file" in
let open (val chrono ~pp_time) in let open (val chrono ~pp_time) in
Format.printf "solve grids in file %S@." file; Format.printf "solve grids in file %S@." file;
@ -365,7 +376,8 @@ let solve_file ~pp_time file =
Format.printf Format.printf
"@[<v>@,#########################@,@[<2>solve grid:@ %a@]@]@." Grid.pp g; "@[<v>@,#########################@,@[<2>solve grid:@ %a@]@]@." Grid.pp g;
let open (val chrono ~pp_time) in let open (val chrono ~pp_time) in
match solve_grid g with let stat = Stat.create () in
(match solve_grid ~stat g with
| None -> Format.printf "no solution%t@." pp_elapsed | None -> Format.printf "no solution%t@." pp_elapsed
| Some g' when not @@ Grid.is_full g' -> | Some g' when not @@ Grid.is_full g' ->
errorf "grid %a@ is not full" Grid.pp g' errorf "grid %a@ is not full" Grid.pp g'
@ -376,7 +388,8 @@ let solve_file ~pp_time file =
g g
| Some g' -> | Some g' ->
Format.printf "@[<v>@[<2>solution%t:@ %a@]@,###################@]@." Format.printf "@[<v>@[<2>solution%t:@ %a@]@,###################@]@."
pp_elapsed Grid.pp g') pp_elapsed Grid.pp g');
if use_stats then Fmt.printf "stats: %a@." Stat.pp stat)
grids; grids;
Format.printf "@.solved %d grids%t@." (List.length grids) pp_elapsed; Format.printf "@.solved %d grids%t@." (List.length grids) pp_elapsed;
() ()
@ -387,17 +400,22 @@ let () =
let files = ref [] in let files = ref [] in
let debug = ref 0 in let debug = ref 0 in
let pp_time = ref true in let pp_time = ref true in
let use_stats = ref false in
let opts = let opts =
[ [
"--debug", Arg.Set_int debug, " debug"; "--debug", Arg.Set_int debug, " debug";
"-d", Arg.Set_int debug, " debug"; "-d", Arg.Set_int debug, " debug";
"--no-time", Arg.Clear pp_time, " do not print solve time"; "--no-time", Arg.Clear pp_time, " do not print solve time";
"--stat", Arg.Set use_stats, " print statistics";
] ]
|> Arg.align |> Arg.align
in in
Arg.parse opts (fun f -> files := f :: !files) "sudoku_solve [options] <file>"; Arg.parse opts (fun f -> files := f :: !files) "sudoku_solve [options] <file>";
Log.set_debug !debug; Log.set_debug !debug;
try List.iter (fun f -> solve_file ~pp_time:!pp_time f) !files try
List.iter
(fun f -> solve_file ~pp_time:!pp_time ~use_stats:!use_stats f)
!files
with Failure msg | Invalid_argument msg -> with Failure msg | Invalid_argument msg ->
Format.printf "@{<Red>Error@}:@.%s@." msg; Format.printf "@{<Red>Error@}:@.%s@." msg;
exit 1 exit 1