-
Notifications
You must be signed in to change notification settings - Fork 2
/
sudoku.v
2185 lines (1918 loc) · 73.6 KB
/
sudoku.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(******************************************************************************)
(* Sudoku.v: *)
(* Checking and Solving Sudokus *)
(* [email protected] *)
(* Definitions: *)
(* sudoku, check, find_one, find_just_one, find_all *)
(* (2022) *)
(* This is a port to mathcomp of the initial sudoku contribution (2006) *)
(******************************************************************************)
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
From mathcomp Require Import all_ssreflect.
From mathcomp Require Import zify.
Section sudoku.
(******************************************************************************)
(* About the encoding: *)
(* h represents the number of rows of a little rectangle *)
(* w represents the number of columns of a little rectangle *)
(* hw represents the number of cells of a little rectangle *)
(* the initial grid is then composed of (hw * hw) cells *)
(* For example for the usual sudoku *)
(* h = 3, w = 3, hw = 9, the grid = 81 cells *)
(* The grid is represented by a seq of (hw * hw) cells *)
(* at the position (x,y) of the seq (i.e at the index (x * hw + y)) *)
(* if the cell is empty it contains 0, otherwise its contains one of *)
(* the numbers 1,2, ; auto., hw *)
(******************************************************************************)
(* Height h and width w *)
Variable h w : nat.
(* Number of cells in a little rectangle *)
Definition hw := h * w.
Lemma h_pos x : x < hw -> 0 < h.
Proof. by rewrite /hw; case: h. Qed.
Lemma w_pos x : x < hw -> 0 < w.
Proof. by rewrite /hw; case: w; rewrite 1?mulnC. Qed.
Lemma hw_divh x : x < hw -> x %/ h < w.
Proof. by move=> xLhw; rewrite ltn_divLR 1?mulnC // (h_pos xLhw). Qed.
Lemma hw_divw x : x < hw -> x %/ w < h.
Proof. by move=> xLhw; rewrite ltn_divLR // (w_pos xLhw). Qed.
Lemma hw_modh x : x < hw -> x %% h < h.
Proof. by move=> xLhw; rewrite ltn_mod (h_pos xLhw). Qed.
Lemma hw_modw x : x < hw -> x %% w < w.
Proof. by move=> xLhw; rewrite ltn_mod // (w_pos xLhw). Qed.
Lemma hw_MhD x y : x < w -> y < h -> x * h + y < hw.
Proof. by rewrite /hw; nia. Qed.
Lemma hw_MwD x y : x < h -> y < w -> x * w + y < hw.
Proof. by rewrite /hw; nia. Qed.
Lemma hw_divhMD x1 z1 : x1 < hw -> z1 < h -> x1 %/ h * h + z1 < hw.
Proof. by move=> x1Lhw z1Lh; apply: hw_MhD => //; apply: hw_divh. Qed.
Lemma hw_divwMD y1 z1 : y1 < hw -> z1 < w -> y1 %/ w * w + z1 < hw.
Proof. by move=> x1Lhw z1Lh; apply: hw_MwD => //; apply: hw_divw. Qed.
Lemma hw_modwMDmod y1 z1 : y1 < hw -> z1 < hw -> y1 %% h * w + z1 %% w < hw.
Proof.
by move=> x1Lhw z1Lh; apply: hw_MwD; [apply: hw_modh|apply: hw_modw].
Qed.
(* The reference seq [1; 2; ; ...; hw] *)
Definition sref := iota 1 hw.
Lemma size_sref : size sref = hw.
Proof. by rewrite size_iota. Qed.
Lemma sref_uniq : uniq sref.
Proof. apply: iota_uniq. Qed.
(* The position indexes [0; 1; 2; ; hw -1] *)
Definition indexes := iota 0 hw.
Lemma size_indexes : size indexes = hw.
Proof. by rewrite size_iota. Qed.
Lemma mem_indexes i : (i \in indexes) = (i < hw).
Proof. by rewrite mem_iota. Qed.
(* An element outside the sref *)
Definition out := 0.
Lemma out_not_in_refl : out \notin sref.
Proof. by rewrite mem_iota /out; lia. Qed.
(******************************************************************************)
(* Positions (x, y) *)
(******************************************************************************)
(* Define a position *)
Definition pos := (nat * nat)%type.
Implicit Types p : pos.
(* Shift a position *)
Definition shift p x y : pos := (x + p.1, y + p.2).
(* A position is valid if it represents a cell of the grid *)
Definition valid_pos p := (p.1 < hw) && (p.2 < hw).
(* Turn a position into a number: *)
(* we number the grid from top to bottom and left to right, i.e. *)
(* (0,0) -> 0, (0,1) -> 1, ..., (hw.-1,hw.-1) -> hw * hw).-1 *)
(* From pos to nat *)
Definition pos2n p := p.1 * hw + p.2.
Lemma pos2n00 : pos2n (0, 0) = 0.
Proof. by []. Qed.
(* The converse *)
Definition n2pos n : pos := (n %/ hw, n %% hw).
Lemma pos2nK n : n < hw * hw -> pos2n (n2pos n) = n.
Proof.
by rewrite /pos2n /n2pos; case: hw => // hw1 _; rewrite -divn_eq.
Qed.
Lemma n2posK p : valid_pos p -> n2pos (pos2n p) = p.
Proof.
case: p => x y /andP[/= xLhw yLhw]; rewrite /pos2n /n2pos /= .
have hw_gt0 : 0 < hw by apply: leq_ltn_trans xLhw.
by rewrite divnMDl // modnMDl divn_small // addn0 modn_small.
Qed.
Lemma valid_pos_pos2n_lt p : valid_pos p -> pos2n p < hw * hw.
Proof. by case: p => x y /andP[/= Hx Hy]; rewrite /pos2n /=; nia. Qed.
(* Positions are unique *)
Lemma valid_pos_eq p1 p2 :
valid_pos p1 -> valid_pos p2 -> pos2n p1 = pos2n p2 -> p1 = p2.
Proof.
case: p1 => x1 y1; case: p2 => x2 y2.
rewrite /valid_pos /pos2n /= =>/andP[x1L y1L] /andP[x2L y2L] HH;
congr (_ , _).
apply: etrans (_ : (x1 * hw + y1) %/ hw = _).
by rewrite divnMDl ?divn_small; lia.
by rewrite HH divnMDl ?divn_small; lia.
apply: etrans (_ : (x1 * hw + y1) %% hw = _).
by rewrite modnMDl ?modn_small; lia.
by rewrite HH modnMDl ?modn_small; lia.
Qed.
(* Find the next position *)
Definition next p : pos := if hw == p.2.+1 then (p.1.+1, 0) else (p.1, p.2.+1).
Lemma next_pos p : pos2n (next p) = (pos2n p).+1.
Proof.
case: p => x y; rewrite /next /pos2n /=.
case: eqP=> Hw /=; lia.
Qed.
Lemma valid_pos_next p :
valid_pos p -> pos2n (next p) < hw * hw -> valid_pos (next p).
Proof.
case: p => x y; rewrite /next /pos2n /valid_pos /= => /andP[Hx Hy].
case: eqP => Hw /=; nia.
Qed.
Lemma valid_pos2n p (s : seq nat) :
valid_pos p -> size s = hw * hw -> pos2n p < size s.
Proof.
case: p => x y; rewrite /valid_pos /pos2n /= => /andP[Hx Hy].
nia.
Qed.
(* the lexical order on positions *)
Definition order_pos :=
[rel p1 p2 | (p1.1 < p2.1) || ((p1.1 == p2.1) && (p1.2 <= p2.2))].
Lemma order_pos_refl p : reflexive order_pos.
Proof. by move=> [x y]; rewrite /= ltnn eqxx leqnn. Qed.
Lemma order_pos_trans : transitive order_pos.
Proof.
move=> [x1 y1] [x2 y2] [x3 y3] /= /orP[x2Lx1|/andP[/eqP-> y2Ly1]].
case/orP => [x1Lx3| /andP[/eqP<-]]; last by rewrite x2Lx1.
by rewrite (ltn_trans x2Lx1 x1Lx3).
by case/orP => [->//|/andP[-> y1Ly3]]; rewrite (leq_trans y2Ly1) // orbT.
Qed.
Lemma order_next_anti p1 p2 :
p1 != p2 -> order_pos p1 p2 = ~~ (order_pos p2 p1).
Proof.
case: p1 => x1 y1; case: p2 => x2 y2 /=.
by rewrite xpair_eqE negb_and; do 2 case: ltngtP.
Qed.
Lemma order_next_pos p1 p2 :
p1 != p2 -> valid_pos p1 -> valid_pos p2 ->
order_pos p1 p2 = order_pos (next p1) p2.
Proof.
case: p1 => x1 y1; case: p2 => x2 y2.
rewrite xpair_eqE negb_and /valid_pos /next /= =>
p1Dp2 /andP[/= Hx1 Hy1] /andP[/= Hx2 Hy2].
repeat (case: eqP => //= ?); repeat (case: leqP => //= ?); lia.
Qed.
Lemma order_pos_00 p : order_pos (0, 0) p.
Proof. by case: p => x y; rewrite /= andbT; case: ltngtP. Qed.
(* Create the seq of positions (x, y) such that 0 <= x < h and 0 <= y < w *)
Definition cross := [seq (x, y) | x <- iota 0 h , y <- iota 0 w].
Lemma mem_cross p : p \in cross = ((p.1 < h) && (p.2 < w)).
Proof.
apply/allpairsP/idP=> [[[x1 y1]/= []]|/andP[Hh Hw]].
by rewrite !mem_iota !andTb !add0n => Hx Hy -> /=; apply/andP.
by exists p; split; rewrite ?mem_iota // -surjective_pairing.
Qed.
(* Create the seq of pairs (x, y) such that 0 <= x < hw and 1 <= y <= hw *)
Definition cross1 := [seq (x, y) | x <- indexes , y <- sref].
Lemma mem_cross1 p : p \in cross1 = ((p.1 \in indexes) && (p.2 \in sref)).
Proof.
apply/allpairsP/idP=> [[[x1 y1]/= [Hx1 Hy1 ->]]|/andP[Hh Hw]].
by rewrite Hx1.
by exists p; rewrite Hh Hw -surjective_pairing.
Qed.
(* Create the seq of positions (x, y) such that *)
(* 0 <= x < hw and 0 <= y < hw1 *)
Definition cross2 := [seq (x, y) | x <- indexes , y <- indexes].
Lemma cross2_uniq : uniq cross2.
Proof.
apply: allpairs_uniq.
- apply: iota_uniq.
- apply: iota_uniq.
by move=> [x1 y1] [x2 y2].
Qed.
Lemma valid_pos_cross2 : all valid_pos cross2.
Proof.
apply/all_allpairsP=> x y.
by rewrite !mem_iota /= add0n /valid_pos => ->.
Qed.
Lemma mem_cross2 p : (p \in cross2) = valid_pos p.
Proof.
case: p => x1 y1; rewrite /valid_pos /=.
apply/allpairsP/idP => [[[x2 y2] /=]|/andP[x1Lw y1Lw]].
by rewrite !mem_iota /= add0n => [] [xLhw yLhw [-> ->]]; rewrite xLhw.
by exists (x1, y1); rewrite !mem_iota; split.
Qed.
(******************************************************************************)
(* Grid *)
(******************************************************************************)
(* A grid is of sequence of values (the contents of the cells) *)
Definition grid := seq nat.
Implicit Types g : grid.
(* Empty grid (initial grid) *)
Definition ginit : grid := nseq (hw * hw) out.
(* Its size *)
Lemma size_ginit : size ginit = hw * hw.
Proof. by rewrite size_nseq. Qed.
(* Get the element of the grid g at position (x, y) *)
Definition get p g := nth out g (pos2n p).
(* The init grid always returns a non-value *)
Lemma get_init p : get p ginit \notin sref.
Proof. by rewrite /get nth_nseq if_same out_not_in_refl. Qed.
(* Relation between get and next *)
Lemma get_next p a g : get (next p) (a :: g) = get p g.
Proof. by rewrite /get next_pos. Qed.
(******************************************************************************)
(* Update *)
(******************************************************************************)
(* sustitute in a sequence s the nth element by v *)
Fixpoint subst (A : Type) (n : nat) (v : A) (s : seq A) : seq A :=
if s is a :: s1 then
if n is n1.+1 then a :: subst n1 v s1 else v :: s1
else [::].
Lemma substE A n (v : A) s :
subst n v s = if n < size s then take n s ++ (v :: drop n.+1 s) else s.
Proof.
elim: n s => /= [[|a s]|/= n IH [|a s]] //=; first by rewrite drop0.
by rewrite {}IH ltnS; case: leqP.
Qed.
Lemma size_subst A n (v : A) s : size (subst n v s) = size s.
Proof.
rewrite substE; case: leqP => //=; rewrite size_cat /= size_take size_drop.
case: leqP => [sLn|nLs] //= _.
by rewrite -subSn // subSS addnC subnK // ltnW.
Qed.
(* Update the grid g at the position (x, y) with the value v *)
Definition update p v g : grid := subst (pos2n p) v g.
(* The size after an update is unchanged *)
Lemma size_update p v g : size (update p v g) = size g.
Proof. by rewrite /update size_subst. Qed.
(* Getting the updated cell gives the new value *)
Lemma update_get p v g :
size g = hw * hw -> valid_pos p -> get p (update p v g) = v.
Proof.
move=> Hs Hp; have := valid_pos2n Hp Hs.
rewrite /update /get substE => pLs.
by rewrite pLs nth_cat size_take pLs ltnn subnn.
Qed.
(* Getting outside the updated cell returns the previous value *)
Lemma update_diff_get p1 p2 v g :
valid_pos p1 -> valid_pos p2 -> p1 != p2 -> get p1 (update p2 v g) = get p1 g.
Proof.
move=> Vp1 Vp2 p1Dp2.
rewrite /get /update substE; case: leqP => //= p2Ls.
rewrite nth_cat size_take p2Ls.
case: leqP => p2Lp1; last by rewrite nth_take.
rewrite leq_eqVlt in p2Lp1; have /orP[/eqP pp2Epp1|pp2Lpp1] := p2Lp1.
by case/eqP : p1Dp2; apply: valid_pos_eq.
rewrite -[_ - _]prednK ?subn_gt0 //= nth_drop.
by rewrite addSnnS prednK ?subn_gt0 // addnC subnK // ltnW.
Qed.
(******************************************************************************)
(* Restrict till position *)
(******************************************************************************)
(* Return the grid where the cells after position p of g are zeroed *)
(* this is used to express an invariable when building the initial grid *)
Definition grestrict p g : grid:=
let n1 := pos2n p in
if n1 < size g then take n1 g ++ (nseq (size g - n1) out) else g.
Lemma grestrict00 g : grestrict (0, 0) g = nseq (size g) out.
Proof. by case: g. Qed.
Lemma grestrict_all p g : size g <= pos2n p -> grestrict p g = g.
Proof. by move=> sLp; rewrite /grestrict ltnNge sLp. Qed.
Lemma grestrict_size p g : size (grestrict p g) = (size g).
Proof.
rewrite /grestrict; case: leqP => // pLg.
by rewrite size_cat size_take pLg size_nseq addnC subnK // ltnW.
Qed.
Lemma grestrict_update p g :
pos2n (next p) <= size g ->
grestrict (next p) g = update p (get p g) (grestrict p g).
Proof.
rewrite /grestrict /get /update substE next_pos.
rewrite leq_eqVlt => /orP[/eqP He|pLg].
have pLg : pos2n p < size g by rewrite He.
rewrite He ltnn eqxx /= size_cat size_take.
rewrite size_nseq pLg addnC subnK; last by rewrite ltnW.
rewrite leqnn take_cat size_take pLg ltnn subnn take0 cats0.
rewrite drop_cat size_take pLg ltnNge (ltnW pLg) /= drop_nseq subnn //=.
rewrite -[LHS](cat_take_drop (pos2n p)) //.
by rewrite (drop_nth out) // drop_oversize // He.
have pLg1 : pos2n p < size g by rewrite ltnW.
rewrite pLg orbT size_cat size_nseq size_take pLg1 ifT; last first.
by rewrite addnC subnK // ltnW.
rewrite take_cat drop_cat !size_take !pLg1 ltnn ifN -?leqNgt ?leqnS //.
rewrite subSn // subnn take0 cats0 drop_nseq subn1 subnS.
by rewrite -cat_rcons (take_nth out).
Qed.
Lemma grestrict_get g p q :
pos2n p < pos2n q -> get p (grestrict q g) = get p g.
Proof.
move=> pLq; rewrite /get /grestrict.
case: leqP => // qLg.
by rewrite nth_cat size_take qLg pLq nth_take.
Qed.
Lemma grestrict_get_default g p q :
pos2n q <= pos2n p -> get p (grestrict q g) = out.
Proof.
move=> qLp; rewrite /get /grestrict.
case: leqP => [gLq|qLg].
by rewrite nth_default // (leq_trans gLq).
by rewrite nth_cat size_take qLg ltnNge qLp /= nth_nseq if_same.
Qed.
(******************************************************************************)
(* Refine *)
(******************************************************************************)
(* A grid refines another if it only substitutes non-sref elements *)
Definition refine g1 g2 :=
[&& size g1 == hw * hw,
size g2 == hw * hw &
[forall n : 'I_(hw * hw),
let p := n2pos n in
(get p g1 \in sref) ==> (get p g1 == get p g2)]].
Lemma refineP g1 g2 :
reflect
[/\ size g1 = hw * hw,
size g2 = hw * hw &
forall p, valid_pos p -> get p g1 \in sref -> get p g1 = get p g2]
(refine g1 g2).
Proof.
apply: (iffP and3P) => [[/eqP Heq1 /eqP Heq2 /forallP /= Hf]|
[Heq1 Heq2 Hf]]; split => //; try by apply/eqP.
move=> [x y] Hp.
have /implyP := Hf (Ordinal (valid_pos_pos2n_lt Hp)).
rewrite /get pos2nK /= //.
by move=> Hk Hg; have /eqP := (Hk Hg).
by apply: valid_pos_pos2n_lt.
apply/forallP=> /= n; rewrite /get pos2nK //.
have hw_pos : 0 < hw.
suff : 0 < hw * hw by case: hw.
by apply: leq_ltn_trans (ltn_ord n).
apply/implyP => Hg; apply/eqP.
have := Hf (n2pos n).
rewrite /get pos2nK //; apply => //.
rewrite /valid_pos /= ltn_mod.
by rewrite ltn_divLR ?ltn_ord /=.
Qed.
Lemma refine_refl g : size g = hw * hw -> refine g g.
Proof. by move=> Hg; apply/refineP; split. Qed.
(* Refinement is transitive *)
Lemma refine_trans : transitive refine.
Proof.
move=> g1 g2 g3 /refineP[Hl1 Hr1 Hf1] /refineP[Hl2 Hr2 Hf2].
apply/refineP; split => //.
by move=> p Hv Hp; rewrite Hf1 // Hf2 // -Hf1.
Qed.
(* Every grid refines the initial grid *)
Lemma refine_init g : size g = hw * hw -> refine ginit g.
Proof.
move=> Hs; apply/refineP; split => //; first by apply size_ginit.
move=> p _; rewrite /ginit /get !nth_nseq if_same => H.
by case/negP: out_not_in_refl.
Qed.
(* update is a refinement *)
Lemma refine_update p v g :
valid_pos p -> get p g \notin sref -> size g = hw * hw ->
refine g (update p v g).
Proof.
move=> Hp Hg Hs; apply/refineP; split=> //; first by rewrite size_update.
move=> p1 Hp1 Hg1.
have hw_gt0 : 0 < hw by case/andP: Hp1; case: hw.
by rewrite update_diff_get //; apply: contra Hg => /eqP<-.
Qed.
Lemma refine_grestrict p g : size g = hw * hw -> refine (grestrict p g) g.
Proof.
move=> Hs.
apply/refineP; split => //.
by rewrite grestrict_size.
move=> p1 Hp1.
case: (leqP (pos2n p) (pos2n p1)) => Lp.
by rewrite grestrict_get_default // => HH; case/negP: out_not_in_refl.
by rewrite grestrict_get.
Qed.
(******************************************************************************)
(* Rows *)
(******************************************************************************)
Definition row i g := take hw (drop (i * hw) g).
Lemma size_row i g :
i < hw -> size g = hw * hw -> size (row i g) = hw.
Proof.
move=> iLhw Hs; rewrite size_take size_drop.
case: leqP => //; nia.
Qed.
(* Relation between get and row *)
Lemma get_row x y g : y < hw -> get (x, y) g = nth out (row x g) y.
Proof.
by move=> yLhw; rewrite /get /row /pos2n /= nth_take // nth_drop.
Qed.
(******************************************************************************)
(* Columns *)
(******************************************************************************)
Fixpoint take_and_drop (A : Type) (t d n : nat) (s : seq A) :=
if n is n1.+1 then take t s ++ take_and_drop t d n1 (drop d s) else [::].
Lemma nth_take_and_drop (A : Type) (a : A) t d m n s :
0 < t <= d -> m < n * t -> n.-1 * d + t <= size s ->
nth a (take_and_drop t d n s) m = nth a s ((m %/ t) * d + m %% t).
Proof.
move=> /andP[t_gt0 tLd].
elim: n m s => //= n IH m s mLtd tdLs.
have tLs : t <= size s.
by rewrite (leq_trans _ tdLs) // leq_addl.
rewrite nth_cat size_take_min (minn_idPl _) //.
case: leqP => [tLm|mLt]; last first.
by rewrite divn_small // add0n modn_small // nth_take.
rewrite {}IH //.
- rewrite nth_drop -{3 4}(subnK tLm).
by rewrite divnDr ?divnn // t_gt0 addn1 mulSn addnA modnDr.
- by rewrite ltn_subLR.
case: n mLtd tdLs => [|n mLtd tdLs]; first by rewrite mul1n ltnNge tLm.
rewrite size_drop leq_subRL //=; first by rewrite addnA -mulSn.
by apply: leq_trans tdLs; rewrite mulSn -addnA leq_addr.
Qed.
Lemma take_and_drop_nil (A : Type) t d n :
take_and_drop t d n [::] = [::] :> seq A.
Proof. by elim: n. Qed.
Lemma size_take_and_drop (A : Type) t d n (s : seq A) :
n.-1 * d + t <= size s ->
size (take_and_drop t d n s) = n * t.
Proof.
elim: n s => [/= //|/= [|n] IH s tLs]; rewrite ?addn0 in tLs.
rewrite size_cat size_take addn0 mul1n; case: ltngtP => //.
by rewrite ltnNge tLs.
rewrite size_cat size_take IH; last first.
rewrite size_drop leq_subRL; first by rewrite addnA.
by rewrite (leq_trans _ tLs) // mulSn -addnA leq_addr.
case: ltngtP => [||<-] //.
by rewrite ltnNge (leq_trans _ tLs) // leq_addl.
Qed.
Definition column i (g : seq nat) := take_and_drop 1 hw hw (drop i g).
Lemma size_column j g :
j < hw -> size g = hw * hw -> size (column j g) = hw.
Proof.
move=> jLhw Hs.
rewrite size_take_and_drop ?muln1 // size_drop {}Hs.
rewrite addn1; nia.
Qed.
(* Relation between get and column *)
Lemma get_column x y g :
size g = hw * hw -> x < hw -> y < hw ->
get (x, y) g = nth out (column y g) x.
Proof.
move=> Hs xLhw yLhw.
rewrite /get /column /pos2n nth_take_and_drop ?muln1 //=.
- by rewrite nth_drop divn1 modn1 addn0 addnC.
- by apply: leq_ltn_trans xLhw.
rewrite size_drop addn1 Hs; nia.
Qed.
(******************************************************************************)
(* SubRectangles *)
(******************************************************************************)
(* The subrectangles *)
Definition rect i g :=
take_and_drop w hw h (drop (w * (i %% h) + h * (i %/ h) * hw) g).
(* Relation between get and rect *)
Lemma get_rect x y g :
size g = hw * hw -> x < hw -> y < hw ->
get (x, y) g =
nth out (rect (x %/ h * h + y %/ w) g) (x %% h * w + y %% w).
Proof.
move=> Hs xLhw yLhw.
have hw_pos : 0 < hw by apply: leq_ltn_trans xLhw.
have h_pos := h_pos xLhw; have w_pos := w_pos xLhw.
have x_d_h := hw_divh xLhw; have x_m_h := hw_modh xLhw.
have y_d_w := hw_divw yLhw; have y_m_w := hw_modw yLhw.
rewrite nth_take_and_drop.
- rewrite nth_drop /get /pos2n /= !divnMDl // !modnMDl.
rewrite modn_small // [(y %/ w)%/ h]divn_small // addn0.
rewrite [(_ %% _)%/ _]divn_small // addn0.
rewrite modn_mod [x in LHS](divn_eq _ h) [y in LHS](divn_eq _ w).
congr nth; lia.
- by rewrite w_pos -[w]mul1n leq_mul2r eqn0Ngt w_pos.
- by rewrite hw_modwMDmod.
rewrite modnMDl divnMDl // modn_small // [(_ %/ _) %/ h]divn_small //.
rewrite addn0 size_drop Hs.
rewrite /hw in hw_pos xLhw yLhw *; nia.
Qed.
Lemma get_rect_rev i j g :
size g = hw * hw -> i < hw -> j < hw ->
get (j %/ h * h + i %/ w, j %% h * w + i %% w) g =
nth out (rect j g) i.
Proof.
move=> Hs iLhw jLhw.
have hw_pos : 0 < hw by apply: leq_ltn_trans iLhw.
have h_pos := h_pos iLhw; have w_pos := w_pos iLhw.
have j_d_h := hw_divh jLhw; have i_m_h := hw_modh jLhw.
have i_d_w := hw_divw iLhw; have i_m_w := hw_modw iLhw.
rewrite get_rect ?hw_MwD ?hw_MhD //.
rewrite !divnMDl // !modnMDl; congr (nth _ (rect _ _) _).
by rewrite (divn_small i_d_w) (divn_small i_m_w) !addn0 -divn_eq.
by rewrite modn_mod (modn_small i_d_w) -divn_eq.
Qed.
Lemma valid_get_rect_rev i1 i2 j1 j2 :
i1 < h -> i2 < w -> j1 < w -> j2 < h -> valid_pos (j1 * h + i1, j2 * w + i2).
Proof.
by move=> i1Lh i2Lw j1Lw j2Lh; rewrite /valid_pos /= hw_MhD // hw_MwD.
Qed.
Lemma size_rect i g :
i < hw -> size g = hw * hw -> size (rect i g) = hw.
Proof.
rewrite /hw => iLhw Hs.
have h_pos := h_pos iLhw; have w_pos := w_pos iLhw.
have i_d_h := hw_divh iLhw; have i_m_h := hw_modh iLhw.
by rewrite size_take_and_drop // size_drop Hs /hw; nia.
Qed.
(******************************************************************************)
(* Sudoku *)
(******************************************************************************)
(* To be a sudoku, the grid should be of the proper hw, rows, columns and *)
(* subrectangle should be a permutation of the reference seq *)
Definition sudoku g :=
[&&
size g == hw * hw,
[forall i : 'I_hw, perm_eq (row i g) sref],
[forall i : 'I_hw, perm_eq (column i g) sref] &
[forall i : 'I_hw, perm_eq (rect i g) sref]].
Lemma sudokuP g :
reflect
[/\
size g = hw * hw,
forall i, i < hw -> perm_eq (row i g) sref,
forall i, i < hw -> perm_eq (column i g) sref &
forall i, i < hw -> perm_eq (rect i g) sref]
(sudoku g).
Proof.
apply: (iffP and4P) => [] [H1 H2 H3 H4]; split; auto.
- by apply/eqP.
- by move=> i iLhw; have /forallP := H2 => /(_ (Ordinal iLhw)).
- by move=> i iLhw; have /forallP := H3 => /(_ (Ordinal iLhw)).
- by move=> i iLhw; have /forallP := H4 => /(_ (Ordinal iLhw)).
- by apply/eqP.
- by apply/forallP => i; apply H2.
- by apply/forallP => i; apply H3.
by apply/forallP => i; apply H4.
Qed.
(******************************************************************************)
(* Literal *)
(******************************************************************************)
(* A literal is composed of two coordinates and a value *)
Definition lit := (pos * nat)%type.
Definition valid_lit l := (l.2 \in sref) && valid_pos l.1.
(******************************************************************************)
(* State *)
(******************************************************************************)
(* A state is an ordered list of positions with their possible values *)
(* the possible values is encoded as a list of booleans, true indicates that *)
(* this value is possible. *)
(* The ordering of the positions is done with respect to the number of *)
(* possities. This means that positions with a small number of possible *)
(* values are top of the list. *)
Definition state := seq (nat * pos * seq bool).
(* ranking value that is stored as the first element of the triple and used *)
(* for the ordering *)
Definition rank_val bs := count (fun x => x == true) (behead bs).
(* Generate the state where all cells have all the possibilities *)
Definition init_state : state :=
let bs := false :: nseq hw true in
let n := rank_val bs in
[seq (n, p, bs) | p <- cross2].
Implicit Type st : state.
Fixpoint add_state n p bs st :=
if st is ((n1, p1, bs1) as t) :: st1 then
if n <= n1 then (n, p, bs) :: st else
t :: add_state n p bs st1
else [:: (n, p, bs)].
(* perform the cons avoiding having tails of false values *)
Definition bcons b bs :=
if b then b :: bs else if bs is _ :: _ then b :: bs else [::].
(* remove the possibility n *)
Fixpoint rm_val n (bs : seq bool) {struct bs} :=
if bs is b :: bs1 then
if n is n1.+1 then bcons b (rm_val n1 bs1) else bcons false bs1
else [::].
(* check if the possibility i is available *)
Definition in_val i bs := nth false bs i.
Lemma in_val_nil i : in_val i [::] = false.
Proof. by rewrite /in_val nth_nil. Qed.
Lemma in_val_rm_val i j bs :
in_val i (rm_val j bs) = (i != j) && in_val i bs.
Proof.
elim: bs i j => [[|i] [|j]|b bs IH [|i] [|j]] //=; first by rewrite andbF.
- by case: bs IH.
- by case: b => //; case: rm_val.
- by case: bs IH => [|b1 bs] IH //=; rewrite in_val_nil.
case: rm_val (IH i j) => [|b2 bs2] /=.
by case: b => /=; rewrite in_val_nil; case: in_val; rewrite (andbT, andbF).
by case: b.
Qed.
Fixpoint update_state p i st :=
if st is ((n1, p1, bs1) as t) :: st1 then
if p == p1 then
let bs2 := rm_val i bs1 in
add_state (rank_val bs2) p bs2 st1 else
add_state n1 p1 bs1 (update_state p i st1)
else [::].
(* list of all positions in a state *)
Definition spos st := [seq (let: (_,p,_) := i in p) | i <- st ].
Lemma perm_spos_add n p i st :
perm_eq (spos (add_state n p i st)) (p :: spos st).
Proof.
elim: st => //= [] [[n1 p1] i1] st IH.
case: leqP => //= _.
by rewrite perm_sym -perm_rcons /= perm_cons perm_rcons perm_sym.
Qed.
Lemma perm_spos_update p i st :
perm_eq (spos (update_state p i st)) (spos st).
Proof.
elim: st => //= [] [[n1 p1] i1] st IH.
case: eqP => /= [<-|_]; first by apply: perm_spos_add.
apply: perm_trans (perm_spos_add _ _ _ _) _.
by rewrite perm_cons.
Qed.
Lemma ulist_update p z st :
uniq (spos st) -> uniq (spos (update_state p z st)).
Proof.
by move=> Hu; rewrite (perm_uniq (perm_spos_update _ _ _)).
Qed.
Lemma spos_init_state : spos init_state = cross2.
Proof. by rewrite /spos -map_comp /=; elim: cross2 => //= a st ->. Qed.
Definition in_state p i st :=
has (fun v => let: (_, p1, v1) := v in (p == p1) && (in_val i v1)) st.
Lemma in_state_add p1 p2 i1 n2 bs2 st :
in_state p1 i1 (add_state n2 p2 bs2 st) =
((p1 == p2) && (in_val i1 bs2)) || in_state p1 i1 st.
Proof.
elim: st => //= [] [[n3 p3] v3] st IH.
case: leqP => Ln2n3 //=.
rewrite IH.
by do 2 case: eqP => //=; do 2 case: in_val.
Qed.
Lemma notin_spos p i st : p \notin spos st -> in_state p i st = false.
Proof.
elim: st => //= [] [[n1 p1] v1] st IH.
by rewrite in_cons !negb_or => /andP[/negPf-> /IH->].
Qed.
Lemma in_state_spos p i st : in_state p i st -> p \in spos st.
Proof.
by case: (_ \in _) (@notin_spos p i st) => // /(_ isT)->.
Qed.
Lemma in_state_update p1 p2 i1 i2 st :
uniq (spos st) ->
in_state p1 i1 (update_state p2 i2 st) =
((p1 != p2) || (i1 != i2)) && in_state p1 i1 st.
Proof.
elim: st => /= [|[[n3 p3] v3] st IH /andP[p3D p3U]]; first by rewrite andbF.
case: eqP p3D => [<-|p1Dp3] p3D /=.
rewrite in_state_add in_val_rm_val.
by (do 2 (case: eqP => //=)) => _ ->; rewrite notin_spos.
rewrite in_state_add IH //.
do 3 case: eqP => //=.
by move=> _ p2E p3E; case: p1Dp3; rewrite -p2E.
Qed.
Lemma in_state_init n p bs :
(n, p, bs) \in init_state =
[&& n == hw, valid_pos p & bs == false :: nseq hw true].
Proof.
have rE : rank_val (false :: nseq hw true) = hw.
by rewrite /rank_val /= count_nseq mul1n.
apply/mapP/idP => /= [[[x y]] /= Hc [-> -> ->] | /and3P[/eqP-> Hc /eqP->]].
by rewrite rE -mem_cross2 Hc !eqxx.
by exists p; rewrite ?rE ?mem_cross2.
Qed.
Lemma in_state_init_state p z :
valid_pos p -> z \in sref -> in_state p z init_state.
Proof.
move=> Hp Hz; apply/hasP.
exists (hw, p, false :: nseq hw true).
by rewrite in_state_init !eqxx Hp.
rewrite eqxx; rewrite mem_iota in Hz.
case: z Hz => //= z; rewrite add1n ltnS => zLhw.
by rewrite /in_val nth_nseq zLhw.
Qed.
Definition valid_state st :=
[/\ uniq (spos st),
forall p, p \in spos st -> valid_pos p &
forall p z, in_state p z st -> z \in sref].
Lemma valid_state_update p z (st : state) :
valid_state st -> valid_state (update_state p z st).
Proof.
move=> [Hu Hv Hw]; split.
- by rewrite (perm_uniq (perm_spos_update _ _ _)) Hu /=.
- move=> p1 Hp1; apply: Hv.
by rewrite (perm_mem (perm_spos_update _ _ _)) in Hp1.
by move=> p1 z1; rewrite in_state_update // => /andP[_ /Hw].
Qed.
Lemma in_state_cons n p v z st : valid_state ((n, p, v) :: st) ->
in_state p z ((n, p, v) :: st) = in_val z v.
Proof.
rewrite /= eqxx /=.
move=> Hv; case: in_val => //=.
apply/negP.
have [/= /andP[Hv1 _] _ _] := Hv.
elim: st {Hv}Hv1 => //= [] [[n1 p1] v1] st IH.
by rewrite inE negb_or; case: eqP.
Qed.
Definition rm_state p st :=
[seq i <- st | let: (_, p1, v1) := i in (p != p1)].
Lemma spos_rm_state st p p1 :
p1 \in spos (rm_state p st) = (p1 != p) && (p1 \in spos st).
Proof.
case: p => x y; elim: st => /= [|[[n [x2 y2]] v] st IH].
by rewrite in_nil andbF.
case: eqP => /= [[<- <-]|]; rewrite !in_cons IH; first by case: eqP.
by do 2 case: eqP => //= ->.
Qed.
Lemma subseq_rm_state p st : subseq (rm_state p st) st.
Proof. by apply: filter_subseq. Qed.
Lemma in_state_rm p1 p2 z st :
in_state p1 z (rm_state p2 st) -> in_state p1 z st.
Proof.
elim: st => //= [] [[n p3] v] st IH.
case: eqP => //= [<- /IH->|_]; first by rewrite orbT.
by case/orP => [->//|/IH->]; rewrite orbT.
Qed.
Lemma notin_state_rm p1 p2 z st :
p1 != p2 -> ~~ in_state p1 z (rm_state p2 st) -> ~~ in_state p1 z st.
Proof.
move=> p1Dp2.
elim: st => //= [] [[n p3] v] st IH.
case: eqP => /= [<- /IH H1|_ ].
by rewrite negb_or negb_and p1Dp2 H1.
by rewrite !negb_or /= => /andP[->].
Qed.
Lemma valid_state_rm_state p st :
valid_state st -> valid_state (rm_state p st).
Proof.
move=> [Hp Hs Ht]; split.
- apply: subseq_uniq Hp.
by apply: map_subseq (subseq_rm_state _ _).
- move=> p1; rewrite spos_rm_state => /andP[_].
by apply: Hs.
by move=> p1 z /in_state_rm/Ht.
Qed.
Lemma rm_state_cons n p v st : valid_state ((n, p, v) :: st) ->
rm_state p ((n, p, v) :: st) = st.
Proof.
rewrite /= eqxx /=.
move=> Hv; have [/= /andP[Hv1 _] _ _] := Hv.
elim: st {Hv}Hv1 => //= [] [[n1 p1] v1] st IH.
rewrite inE negb_or; case: eqP => //= ? ?.
by rewrite IH.
Qed.
(* Given a literal that we know that holds generate the seq of literals
that we know cannot hold *)
Definition update_anti_literals (p : pos) z (st : state) : state :=
let: (x, y) := p in
let st1 := foldr (fun x1 st => if x == x1 then st else
update_state (x1, y) z st) st indexes in
let st2 := foldr (fun y1 st => if y == y1 then st else
update_state (x, y1) z st) st1 indexes in
let x1 := x %/ h * h in
let y1 := y %/ w * w in
let st3 := foldr (fun p1 st => if p == shift p1 x1 y1 then st else
update_state (shift p1 x1 y1) z st) st2 cross in
st3.
Definition anti_literals (l : lit) : seq lit :=
let: ((x, y), z) := l in
let rx1 := x %/ h * h in
let ry1 := y %/ w * w in
[seq ((x, y1), z) | y1 <- indexes & y != y1 ] ++
[seq ((x1, y), z) | x1 <- indexes & x != x1 ] ++
[seq (shift p rx1 ry1, z) | p <- cross & (x, y) != shift p rx1 ry1].
Lemma eqz_anti_literals p1 p2 z1 z2 :
(p1, z1) \in anti_literals (p2, z2) -> z1 = z2.
Proof. by case: p2 => x2 y2; rewrite !mem_cat => /or3P[] /mapP[x _] []. Qed.
Lemma valid_pos_anti_literals p1 p2 z1 z2 :
(p1, z1) \in anti_literals (p2, z2) -> valid_pos p2 -> valid_pos p1.
Proof.
case: p1 => x1 y1; case: p2 => x2 y2.
rewrite !mem_cat => /or3P[] /mapP[x];
rewrite mem_filter ?mem_iota ?mem_cross ?add0n /= =>
/andP[Hd Hhw] [-> -> _] /andP[/= x2Lhw y2Lhw]; rewrite /valid_pos /=.
- by rewrite x2Lhw Hhw.
- by rewrite Hhw y2Lhw.
have /andP[x1Lh x2Lw] := Hhw.
by rewrite hw_divhMD // hw_divwMD.
Qed.
Lemma anti_literals_swap p1 p2 z1 z2 :
valid_pos p1 -> (p2, z2) \in anti_literals (p1, z1) ->
(p1, z1) \in anti_literals (p2, z2).
Proof.
case: p1 => x1 y1; case: p2 => x2 y2 => /andP[/= x1Lhw y1Lhw].
rewrite !mem_cat => /or3P[] /mapP[x];
rewrite mem_filter ?mem_iota ?mem_cross ?add0n =>
/andP[Hd Hhw] [-> -> ->].
- apply/or3P; apply: Or31.
by rewrite map_f // mem_filter // eq_sym Hd mem_iota.
- apply/or3P; apply: Or32.
by rewrite map_f // mem_filter // eq_sym Hd mem_iota.
apply/or3P; apply: Or33.
have h_pos := h_pos x1Lhw; have w_pos := w_pos x1Lhw.
have /andP[x1Lh x2Lw] := Hhw.
rewrite !divnMDl // (divn_small x1Lh) (divn_small x2Lw) !addn0.
have ->: (x1, y1) = shift (x1 %% h, y1 %% w) (x1 %/ h * h) (y1 %/ w * w).
by rewrite /shift /= -!divn_eq.
rewrite map_f // mem_filter mem_cross /= hw_modh // hw_modw // !andbT.
rewrite /shift /= xpair_eqE {1}(divn_eq x1 h)
{1}(divn_eq y1 w) !eqn_add2l eq_sym [_ == x.2]eq_sym in Hd.
by rewrite /shift /= xpair_eqE /= !eqn_add2l.
Qed.
Lemma anti_literals_nswap p1 p2 z1 z2 :
valid_pos p2 -> (p2, z2) \notin anti_literals (p1, z1) ->
(p1, z1) \notin anti_literals (p2, z2).
Proof. by move=> Hp2; apply/contra/anti_literals_swap. Qed.
Lemma notin_anti_literals l : l \notin anti_literals l.
Proof.
case: l => [] [x y] z.
rewrite !mem_cat !negb_or; apply/and3P; split; apply/negP=> /mapP.
- by move=> [y1 Hy1 [yE]]; rewrite yE mem_filter eqxx in Hy1.
- by move=> [x1 Hx1 [xE]]; rewrite xE mem_filter eqxx in Hx1.
- move=> [[x2 y2] Hxy2 [xE yE]].
by rewrite mem_filter xpair_eqE /= -xE -yE !eqxx in Hxy2.
Qed.
Lemma anti_literals_valid_lit l :
valid_lit l -> all valid_lit (anti_literals l).
Proof.
case: l => [] [x y] z /andP[/= Hz /andP[/= Hx Hy]]; rewrite !all_cat.
apply/and3P; split; apply/allP => i /mapP [j];
rewrite mem_filter => /andP[Hd Hj] ->; apply/andP; split => //=.
- by apply/andP; split=> //=; rewrite mem_iota in Hj.
- by apply/andP; split=> //=; rewrite mem_iota in Hj.
rewrite mem_cross in Hj; case/andP: Hj => Hj1 Hj2.
apply: valid_get_rect_rev=> //.