1
1
(* * simple sudoku solver *)
2
2
3
- module Fmt = CCFormat
4
- module Vec = Sidekick_util. Vec
5
- module Log = Sidekick_util. Log
6
- module Profile = Sidekick_util. Profile
3
+ open Sidekick_util
7
4
8
5
let errorf msg = Fmt. kasprintf failwith msg
9
6
@@ -147,74 +144,73 @@ module Solver : sig
147
144
val create : Grid .t -> t
148
145
val solve : t -> Grid .t option
149
146
end = struct
150
- open Sidekick_sat.Solver_intf
147
+ open Sidekick_core
151
148
152
- (* formulas *)
153
- module F = struct
154
- type t = bool * int * int * Cell .t
149
+ type Const.view + = Cell_is of { x : int ; y : int ; value : Cell .t }
155
150
156
- let equal (sign1 , x1 , y1 , c1 ) (sign2 , x2 , y2 , c2 ) =
157
- sign1 = sign2 && x1 = x2 && y1 = y2 && Cell. equal c1 c2
151
+ let ops =
152
+ (module struct
153
+ let pp out = function
154
+ | Cell_is { x; y; value } ->
155
+ Fmt. fprintf out " (%d:%d=%a)" x y Cell. pp value
156
+ | _ -> ()
158
157
159
- let hash (sign , x , y , c ) =
160
- CCHash. (combine4 (bool sign) (int x) (int y) (Cell. hash c))
158
+ let hash = function
159
+ | Cell_is { x; y; value } ->
160
+ Hash. (combine3 (int x) (int y) (Cell. hash value))
161
+ | _ -> assert false
161
162
162
- let pp out (sign , x , y , c ) =
163
- Fmt. fprintf out " [@[(%d,%d) %s %a@]]" x y
164
- (if sign then
165
- " ="
166
- else
167
- " !=" )
168
- Cell. pp c
169
-
170
- let neg (sign , x , y , c ) = not sign, x, y, c
163
+ let equal a b =
164
+ match a, b with
165
+ | Cell_is a , Cell_is b ->
166
+ a.x = b.x && a.y = b.y && Cell. equal a.value b.value
167
+ | _ -> false
168
+ end : Const. DYN_OPS )
171
169
172
- let norm_sign ((sign , _ , _ , _ ) as f ) =
173
- if sign then
174
- f, true
175
- else
176
- neg f, false
177
-
178
- let make sign x y (c : Cell.t ) : t = sign, x, y, c
179
- end
170
+ module Sat = Sidekick_sat
180
171
181
- module Theory = struct
182
- include Sidekick_sat.Proof_dummy. Make (F )
172
+ let mk_cell tst x y value : Term.t =
173
+ Term. const tst
174
+ @@ Const. make (Cell_is { x; y; value }) ops ~ty: (Term. bool tst)
183
175
184
- type proof = unit
185
- type proof_step = unit
176
+ let mk_cell_lit ? sign tst x y value : Lit.t =
177
+ Lit. atom ?sign @@ mk_cell tst x y value
186
178
187
- module Lit = F
179
+ module Theory : sig
180
+ type t
188
181
189
- type lit = Lit .t
190
- type t = { grid : Grid .t B_ref .t }
182
+ val grid : t -> Grid .t
183
+ val create : Term .store -> Grid .t -> t
184
+ val to_plugin : t -> Sat .plugin
185
+ end = struct
186
+ type t = { tst : Term .store ; grid : Grid .t B_ref .t }
191
187
192
- let create g : t = { grid = B_ref. create g }
193
188
let [@ inline] grid self : Grid. t = B_ref. get self.grid
194
189
let [@ inline] set_grid self g : unit = B_ref. set self.grid g
195
190
let push_level self = B_ref. push_level self.grid
196
191
let pop_levels self n = B_ref. pop_levels self.grid n
197
- let pp_c_ = Fmt. (list ~sep: (return " @ ∨ " )) F . pp
192
+ let pp_c_ = Fmt. (list ~sep: (return " @ ∨ " )) Lit . pp
198
193
199
194
let [@ inline] logs_conflict kind c : unit =
200
195
Log. debugf 4 (fun k -> k " (@[conflict.%s@ %a@])" kind pp_c_ c)
201
196
202
197
(* check that all cells are full *)
203
- let check_full_ (self : t ) (acts : (Lit.t, proof, proof_step) acts ) : unit =
204
- Profile. with_ " check-full" @@ fun () ->
198
+ let check_full_ (self : t ) (acts : Sat. acts ) : unit =
199
+ (* let@ () = Profile.with_ "check-full" in *)
205
200
let (module A ) = acts in
206
201
Grid. all_cells (grid self) (fun (x , y , c ) ->
207
202
if Cell. is_empty c then (
208
203
let c =
209
- CCList. init 9 (fun c -> F. make true x y (Cell. make (c + 1 )))
204
+ CCList. init 9 (fun c ->
205
+ mk_cell_lit self.tst x y (Cell. make (c + 1 )))
210
206
in
211
207
Log. debugf 4 (fun k -> k " (@[add-clause@ %a@])" pp_c_ c);
212
- A. add_clause ~keep: true c ()
208
+ A. add_clause ~keep: true c Proof_trace. dummy_step_id
213
209
))
214
210
215
211
(* check constraints *)
216
- let check_ (self : t ) (acts : (Lit.t, proof, proof_step) acts ) : unit =
217
- Profile. with_ " check-constraints" @@ fun () ->
212
+ let check_ (self : t ) (acts : Sat. acts ) : unit =
213
+ (* let@ () = Profile.with_ "check-constraints" in *)
218
214
Log. debugf 4 (fun k ->
219
215
k " (@[sudoku.check@ @[:g %a@]@])" Grid. pp (B_ref. get self.grid));
220
216
let (module A ) = acts in
@@ -229,77 +225,103 @@ end = struct
229
225
pairs (fun ((x1 , y1 , c1 ), (x2 , y2 , c2 )) ->
230
226
if Cell. equal c1 c2 then (
231
227
assert (x1 <> x2 || y1 <> y2);
232
- let c = [ F. make false x1 y1 c1; F. make false x2 y2 c2 ] in
228
+ let c =
229
+ [
230
+ mk_cell_lit self.tst ~sign: false x1 y1 c1;
231
+ mk_cell_lit self.tst ~sign: false x2 y2 c2;
232
+ ]
233
+ in
233
234
logs_conflict (" all-diff." ^ kind) c;
234
- A. raise_conflict c ()
235
+ A. raise_conflict c Proof_trace. dummy_step_id
235
236
))
236
237
in
237
238
all_diff " rows" Grid. rows;
238
239
all_diff " cols" Grid. cols;
239
240
all_diff " squares" Grid. squares;
240
241
()
241
242
242
- let trail_ (acts : (Lit.t, proof, proof_step) acts ) =
243
+ let trail_ (acts : Sat. acts ) =
243
244
let (module A ) = acts in
244
245
A. iter_assumptions
245
246
246
247
(* update current grid with the given slice *)
247
- let add_slice (self : t ) (acts : (Lit.t, proof, proof_step) acts ) : unit =
248
+ let add_slice (self : t ) (acts : Sat. acts ) : unit =
248
249
let (module A ) = acts in
249
- trail_ acts (function
250
- | false , _ , _ , _ -> ()
251
- | true , x , y , c ->
252
- assert (Cell. is_full c);
253
- let grid = grid self in
254
- let c' = Grid. get grid x y in
255
- if Cell. is_empty c' then
256
- set_grid self (Grid. set grid x y c)
257
- else if Cell. neq c c' then (
258
- (* conflict: at most one value *)
259
- let c = [ F. make false x y c; F. make false x y c' ] in
260
- logs_conflict " at-most-one" c;
261
- A. raise_conflict c ()
262
- ))
250
+ trail_ acts (fun lit ->
251
+ match Lit. sign lit, Term. view (Lit. term lit) with
252
+ | true , E_const { Const. c_view = Cell_is { x; y; value = c } ; _ } ->
253
+ assert (Cell. is_full c);
254
+ let grid = grid self in
255
+ let c' = Grid. get grid x y in
256
+ if Cell. is_empty c' then
257
+ set_grid self (Grid. set grid x y c)
258
+ else if Cell. neq c c' then (
259
+ (* conflict: at most one value *)
260
+ let c =
261
+ [
262
+ mk_cell_lit self.tst ~sign: false x y c;
263
+ mk_cell_lit self.tst ~sign: false x y c';
264
+ ]
265
+ in
266
+ logs_conflict " at-most-one" c;
267
+ A. raise_conflict c Proof_trace. dummy_step_id
268
+ )
269
+ | _ -> () )
263
270
264
271
let partial_check (self : t ) acts : unit =
265
- Profile. with_ " partial-check" @@ fun () ->
272
+ (* let@ () = Profile.with_ "partial-check" in *)
266
273
Log. debugf 4 (fun k ->
267
- k " (@[sudoku.partial-check@ :trail [@[%a@]]@])" (Fmt. list F . pp)
268
- (trail_ acts |> Iter. to_list ));
274
+ k " (@[sudoku.partial-check@ :trail [@[%a@]]@])" (Fmt. iter Lit . pp)
275
+ (trail_ acts));
269
276
add_slice self acts;
270
277
check_ self acts
271
278
272
279
let final_check (self : t ) acts : unit =
273
- Profile. with_ " final-check" @@ fun () ->
280
+ (* let@ () = Profile.with_ "final-check" in *)
274
281
Log. debugf 4 (fun k -> k " (@[sudoku.final-check@])" );
275
282
check_full_ self acts;
276
283
check_ self acts
277
- end
278
284
279
- module S = Sidekick_sat. Make_cdcl_t (Theory )
285
+ let create tst g : t = { tst; grid = B_ref. create g }
286
+
287
+ let to_plugin (self : t ) : Sat.plugin =
288
+ Sat. mk_plugin_cdcl_t
289
+ ~push_level: (fun () -> push_level self)
290
+ ~pop_levels: (fun n -> pop_levels self n)
291
+ ~partial_check: (partial_check self) ~final_check: (final_check self) ()
292
+ end
280
293
281
- type t = { grid0 : Grid .t ; solver : S .t }
294
+ type t = { grid0 : Grid .t ; tst : Term .store ; theory : Theory .t ; solver : Sat .t }
282
295
283
296
let solve (self : t ) : _ option =
284
- Profile. with_ " sudoku.solve" @@ fun () ->
297
+ let @ () = Profile. with_ " sudoku.solve" in
285
298
let assumptions =
286
299
Grid. all_cells self.grid0
287
300
|> Iter. filter (fun (_ , _ , c ) -> Cell. is_full c)
288
- |> Iter. map (fun (x , y , c ) -> F. make true x y c)
301
+ |> Iter. map (fun (x , y , c ) -> mk_cell_lit self.tst x y c)
289
302
|> Iter. to_rev_list
290
303
in
291
304
Log. debugf 2 (fun k ->
292
- k " (@[sudoku.solve@ :assumptions %a@])" (Fmt.Dump. list F. pp) assumptions);
305
+ k " (@[sudoku.solve@ :assumptions %a@])" (Fmt.Dump. list Lit. pp)
306
+ assumptions);
293
307
let r =
294
- match S . solve self.solver ~assumptions with
295
- | S .Sat _ -> Some (Theory. grid ( S. theory self.solver) )
296
- | S .Unsat _ -> None
308
+ match Sat . solve self.solver ~assumptions with
309
+ | Sat .Sat _ -> Some (Theory. grid self.theory )
310
+ | Sat .Unsat _ -> None
297
311
in
298
312
(* TODO: print some stats *)
299
313
r
300
314
301
315
let create g : t =
302
- { solver = S. create ~proof: () (Theory. create g); grid0 = g }
316
+ let tst = Term.Store. create () in
317
+ let theory = Theory. create tst g in
318
+ let plugin : Sat.plugin = Theory. to_plugin theory in
319
+ {
320
+ tst;
321
+ solver = Sat. create ~proof: Proof_trace. dummy plugin;
322
+ theory;
323
+ grid0 = g;
324
+ }
303
325
end
304
326
305
327
let solve_grid (g : Grid.t ) : Grid.t option =
@@ -320,7 +342,7 @@ let chrono ~pp_time : (module CHRONO) =
320
342
(module M )
321
343
322
344
let solve_file ~pp_time file =
323
- Profile. with_ " solve-file" @@ fun () ->
345
+ let @ () = Profile. with_ " solve-file" in
324
346
let open (val chrono ~pp_time ) in
325
347
Format. printf "solve grids in file %S@." file ;
326
348
@@ -360,7 +382,7 @@ let solve_file ~pp_time file =
360
382
()
361
383
362
384
let () =
363
- Sidekick_tef. with_setup @@ fun () ->
385
+ let @ () = Sidekick_tef. with_setup in
364
386
Fmt. set_color_default true ;
365
387
let files = ref [] in
366
388
let debug = ref 0 in
0 commit comments