Skip to content

Instantly share code, notes, and snippets.

@noughtmare
Last active November 10, 2024 22:24
Show Gist options
  • Save noughtmare/6d2d7d1be433a4ccd1dd1f9f4bff36df to your computer and use it in GitHub Desktop.
Save noughtmare/6d2d7d1be433a4ccd1dd1f9f4bff36df to your computer and use it in GitHub Desktop.
Modeling correct-by-construction Sudoku in Agda
open import Data.Fin as Fin using (Fin ; #_ ; _≟_)
open import Data.Fin.Properties using (suc-injective)
open import Level as Level using (Level)
open import Data.Unit using (⊤ ; tt)
open import Data.Empty
open import Data.Product as Product
open import Data.Product.Properties as Product using (,-injective ; ≡-dec)
open import Data.Sum
open import Relation.Binary.PropositionalEquality
open import Data.Nat using (ℕ ; _+_)
open import Data.Nat.Literals as Nat
open import Data.Fin.Literals as Fin
open import Level.Literals as Lvl
open import Agda.Builtin.FromNat
open import Data.Vec as Vec using (Vec ; _∷_ ; [])
import Data.Vec.Properties as Vec
open import Relation.Nullary.Decidable
open import Function using (case_of_ ; _↔_ ; mk↔ₛ′)
open import Relation.Binary using (DecidableEquality)
instance
NumFin : {n} Number (Fin n)
NumFin {n} = Fin.number n
NumNat : Number ℕ
NumNat = Nat.number
-- NumLvl : Number Level
-- NumLvl = Lvl.Levelℕ
--
-- variable ℓ : Level
Rel : Set Set Set₁
Rel A B = A B Set
Irrelevant : {A B} Rel A B Set
Irrelevant R = {a b} (x y : R a b) x ≡ y
Cell Num Row Col Blk : Set
Num = Fin 4
Row = Fin 4
Col = Fin 4
Blk = Fin 4
Cell = Row × Col
R : Rel Row Cell
R row (row′ , _) = row ≡ row′
C : Rel Col Cell
C col (_ , col′) = col ≡ col′
lookup2 : {A : Set} {n m} Vec (Vec A n) m Fin m × Fin n A
lookup2 v (r , c) = Vec.lookup (Vec.lookup v r) c
B : Rel Blk Cell
B b (r , c) = b ≡ lookup2
((0011 ∷ []) ∷
(0011 ∷ []) ∷
(2233 ∷ []) ∷
(2233 ∷ []) ∷ [])
(r , c)
Cell′ : Set
Cell′ = Blk × Fin 4
B′ : Rel Blk Cell′
B′ b (b′ , _) = b ≡ b′
rel→ʳ : {A B B′} (B′ B) Rel A B Rel A B′
rel→ʳ from R x y = R x (from y)
rel→ˡ : {A A′ B} (A′ A) Rel A B Rel A′ B
rel→ˡ from R x y = R (from x) y
_∘_ : {A B C : Set} Rel A B Rel B C Rel A C
(R ∘ S) x z = ∃[ y ] R x y × S y z
open Function.Inverse
∘→ : {A B B′ C} {R : Rel A B} {S : Rel B C} (f : B ↔ B′) x y (R ∘ S) x y (rel→ʳ (f .from) R ∘ rel→ˡ (f .from) S) x y
∘→ {R = R} {S} f _ _ (x , r , s) = f .to x , subst (λ X R _ X) (sym (proj₂ (f .inverse) refl)) r , subst (λ X S X _) (sym (proj₂ (f .inverse) refl)) s
record Sudoku : Set₁ where
field
N : Rel Cell Num
distinct-r : Irrelevant (R ∘ N)
distinct-c : Irrelevant (C ∘ N)
distinct-b : Irrelevant (B ∘ N)
open Sudoku
dec-fin : {n} {f : Fin n Set} ( x Dec (f x)) Dec ( x f x)
dec-fin {ℕ.zero} _ = yes (λ ())
dec-fin {ℕ.suc n} f with f Fin.zero | dec-fin (λ i f (Fin.suc i))
... | yes x | yes y = yes λ where
Fin.zero x
(Fin.suc i) y i
... | yes x | no y = no λ f y (λ i f (Fin.suc i))
... | no x | _ = no (λ f x (f Fin.zero))
dec-distinct₁ : {A : Set} {n} (_ : DecidableEquality A) (x : A) (f : Fin n A) Dec ( i x ≢ f i)
dec-distinct₁ {n = ℕ.zero} _≟_ x f = yes (λ ())
dec-distinct₁ {n = ℕ.suc n} _≟_ x f with x ≟ f Fin.zero | dec-distinct₁ {n = n} _≟_ x (λ i f (Fin.suc i))
... | yes x | _ = no (λ f f Fin.zero x)
... | no x | yes y = yes λ where
Fin.zero x₂ x x₂
(Fin.suc i) x₂ y i x₂
... | no x | no y = no (λ f y λ i f (Fin.suc i))
dec-distinct : {A : Set} {n} (_ : DecidableEquality A) (f : Fin n A) Dec ( i j (f i ≡ f j) i ≡ j)
dec-distinct {n = ℕ.zero} _≟_ f = yes (λ _ ())
dec-distinct {n = ℕ.suc n} _≟_ f with dec-distinct₁ _≟_ (f Fin.zero) (λ i f (Fin.suc i)) | dec-distinct _≟_ (λ i f (Fin.suc i))
... | yes x | yes y = yes λ where
Fin.zero Fin.zero _ refl
Fin.zero (Fin.suc j) z case x j z of λ ()
(Fin.suc i) Fin.zero z case x i (sym z) of λ ()
(Fin.suc i) (Fin.suc j) z cong Fin.suc (y i j z)
... | yes _ | no y = no λ f y (λ i j x suc-injective (f (Fin.suc i) (Fin.suc j) x))
... | no x | _ = no λ f x λ i x₁ case f Fin.zero (Fin.suc i) x₁ of λ ()
-- Slower but simpler :)
-- dec-distinct _≟_ f = dec-fin (λ i → dec-fin λ j →
-- case i Fin.≟ j of λ where
-- (yes x) → yes (λ _ → x)
-- (no x) → case f i ≟ f j of λ where
-- (yes y) → no λ z → x (z y)
-- (no y) → yes (λ z → ⊥-elim (y z)))
board : Vec (Vec Num 4) 4
board = ((0123 ∷ []) ∷
(2301 ∷ []) ∷
(1032 ∷ []) ∷
(3210 ∷ []) ∷ [])
blkBoard : Vec (Vec Cell 4) 4
blkBoard = (((0 , 0) ∷ (0 , 1) ∷ (1 , 0) ∷ (1 , 1) ∷ []) ∷
((0 , 2) ∷ (0 , 3) ∷ (1 , 2) ∷ (1 , 3) ∷ []) ∷
((2 , 0) ∷ (2 , 1) ∷ (3 , 0) ∷ (3 , 1) ∷ []) ∷
((2 , 2) ∷ (2 , 3) ∷ (3 , 2) ∷ (3 , 3) ∷ []) ∷ [])
cell↔cell′ : Cell ↔ Cell′
cell↔cell′ = mk↔ₛ′
(lookup2 blkBoard)
(lookup2 blkBoard)
(λ where (x , y) from-yes (dec-fin (λ x dec-fin (λ y ≡-dec _≟_ _≟_ (lookup2 blkBoard (lookup2 blkBoard (x , y))) (x , y)))) x y)
(λ where (x , y) from-yes (dec-fin (λ x dec-fin (λ y ≡-dec _≟_ _≟_ (lookup2 blkBoard (lookup2 blkBoard (x , y))) (x , y)))) x y)
-- blk-ix→cell : Blk × Fin 4 → Cell
-- blk-ix→cell = lookup2 blkBoard
B→B′ : x y rel→ʳ (cell↔cell′ .from) B x y B′ x y
B→B′ x (Fin.zero , Fin.zero) refl = refl
B→B′ x (Fin.zero , Fin.suc Fin.zero) refl = refl
B→B′ x (Fin.zero , Fin.suc (Fin.suc Fin.zero)) refl = refl
B→B′ x (Fin.zero , Fin.suc (Fin.suc (Fin.suc Fin.zero))) refl = refl
B→B′ x (Fin.suc Fin.zero , Fin.zero) refl = refl
B→B′ x (Fin.suc Fin.zero , Fin.suc Fin.zero) refl = refl
B→B′ x (Fin.suc Fin.zero , Fin.suc (Fin.suc Fin.zero)) refl = refl
B→B′ x (Fin.suc Fin.zero , Fin.suc (Fin.suc (Fin.suc Fin.zero))) refl = refl
B→B′ x (Fin.suc (Fin.suc Fin.zero) , Fin.zero) refl = refl
B→B′ x (Fin.suc (Fin.suc Fin.zero) , Fin.suc Fin.zero) refl = refl
B→B′ x (Fin.suc (Fin.suc Fin.zero) , Fin.suc (Fin.suc Fin.zero)) refl = refl
B→B′ x (Fin.suc (Fin.suc Fin.zero) , Fin.suc (Fin.suc (Fin.suc Fin.zero))) refl = refl
B→B′ x (Fin.suc (Fin.suc (Fin.suc Fin.zero)) , Fin.zero) refl = refl
B→B′ x (Fin.suc (Fin.suc (Fin.suc Fin.zero)) , Fin.suc Fin.zero) refl = refl
B→B′ x (Fin.suc (Fin.suc (Fin.suc Fin.zero)) , Fin.suc (Fin.suc Fin.zero)) refl = refl
B→B′ x (Fin.suc (Fin.suc (Fin.suc Fin.zero)) , Fin.suc (Fin.suc (Fin.suc Fin.zero))) refl = refl
-- ∘→ : ∀{A B B′ C} {R : Rel A B} {S : Rel B C} → (f : B ↔ B′) → ∀{x y} → (R ∘ S) x y → (rel→ʳ (f .from) R ∘ rel→ˡ (f .from) S) x y
map2 : {n m} {A B : Set} (A B) Vec (Vec A m) n Vec (Vec B m) n
map2 f v = Vec.map (Vec.map f) v
lookup2-map2 : {m n A B} {f : A B} {v : Vec (Vec A m) n} {i : Fin n × Fin m} lookup2 (map2 f v) i ≡ f (lookup2 v i)
lookup2-map2 {f = f} {v = v} {i = r , c} = trans (cong (λ X Vec.lookup X c) (Vec.lookup-map r (Vec.map f) v)) (Vec.lookup-map c f (Vec.lookup v r))
test : Sudoku
test .N (r , c) w = w ≡ lookup2 board (r , c)
test .distinct-r ((r , c₁) , refl , refl) ((.r , c₂) , refl , N) with from-yes (dec-fin (λ i dec-distinct _≟_ (λ j lookup2 board (i , j)))) r c₁ c₂ N | N
... | refl | refl = refl
test .distinct-c ((r₁ , c) , refl , refl) ((r₂ , .c) , refl , N) with from-yes (dec-fin (λ j dec-distinct _≟_ (λ i lookup2 board (i , j)))) c r₁ r₂ N | N
... | refl | refl = refl
test .distinct-b {a} {b} x y with ∘→ {A = Blk} {B = Cell} {B′ = Cell′} {C = Num} {R = B} {S = test .N} cell↔cell′ a b x | ∘→ {A = Blk} {B = Cell} {C = Num} {R = B} {S = test .N} cell↔cell′ a b y
test .distinct-b {a} {b} x y | ((b₁ , i₁) , B₁ , refl) | ((b₂ , i₂) , B₂ , N) with B→B′ a (b₁ , i₁) B₁ | B→B′ a (b₂ , i₂) B₂
test .distinct-b x y | ((b , i₁) , _ , refl) | ((.b , i₂) , _ , N) | refl | refl with from-yes (dec-fin (λ i dec-distinct _≟_ (λ j lookup2 board (i , j)))) b i₁ i₂ (trans (lookup2-map2 {f = lookup2 board} {v = blkBoard} {i = b , i₁}) (trans N (sym (lookup2-map2 {f = lookup2 board} {v = blkBoard} {i = b , i₂})))) | N
... | refl | refl = {!!}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment