{-# OPTIONS --exact-split #-}
{-# OPTIONS --guardedness #-}
{-# OPTIONS --no-sized-types #-}
{-# OPTIONS --safe #-}
{-# OPTIONS --warning=all #-}
{-# OPTIONS --warning=error #-}
module Lecture.ReasoningAboutPrograms.InsertSort where
open import Data.Empty
open import Data.Nat renaming (suc to succ)
open import Data.Product
open import Data.List
open import Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary
import Relation.Binary.PreorderReasoning as Pre
infix 4 _≙_
insert : ℕ → List ℕ → List ℕ
insert n [] = n ∷ []
insert n (x ∷ xs) with n ≤? x
... | yes _ = n ∷ x ∷ xs
... | no _ = x ∷ insert n xs
insertEg₁ : List ℕ
insertEg₁ = insert 4 (2 ∷ 5 ∷ [])
insertEg₂ : List ℕ
insertEg₂ = insert 4 (24 ∷ 50 ∷ [])
sortW : List ℕ → List ℕ
sortW [] = []
sortW (x ∷ xs) = insert x (sortW xs)
¬x≤y→y≤x : ∀ {m n} → ¬ (m ≤ n) → n ≤ m
¬x≤y→y≤x {m} {zero} _ = z≤n
¬x≤y→y≤x {zero} {succ n} ¬m≤Sn = ⊥-elim (¬m≤Sn z≤n)
¬x≤y→y≤x {succ m} {succ n} ¬m≤Sn = s≤s (¬x≤y→y≤x (λ m≤n → ¬m≤Sn (s≤s m≤n)))
data Sorted : List ℕ → Set where
sorted-[] : Sorted []
sorted-x : ∀ n → Sorted (n ∷ [])
sorted-∷ : ∀ {m n xs} → m ≤ n → Sorted (n ∷ xs) → Sorted (m ∷ n ∷ xs)
2357-sorted : Sorted (2 ∷ 3 ∷ 5 ∷ 7 ∷ [])
2357-sorted = sorted-∷ (s≤s (s≤s z≤n))
(sorted-∷ (s≤s (s≤s (s≤s z≤n)))
(sorted-∷ (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))
(sorted-x (succ (succ (succ (succ (succ (succ (succ zero))))))))))
tailSorted : ∀ {x} {xs} → Sorted (x ∷ xs) → Sorted xs
tailSorted {x} (sorted-x .x) = sorted-[]
tailSorted (sorted-∷ h₁ h₂) = h₂
occ : ℕ → List ℕ → ℕ
occ n [] = 0
occ n (x ∷ xs) with n ≟ x
... | yes _ = 1 + occ n xs
... | no _ = occ n xs
occEg₁ : ℕ
occEg₁ = occ 3 (3 ∷ 7 ∷ 3 ∷ [])
occEg₂ : ℕ
occEg₂ = occ 36725 (3 ∷ 7 ∷ 3 ∷ [])
_≙_ : List ℕ → List ℕ → Set
xs ≙ ys = (n : ℕ) → occ n xs ≡ occ n ys
≙-refl : ∀ xs → xs ≙ xs
≙-refl xs n = refl
≙-sym : ∀ xs ys → xs ≙ ys → ys ≙ xs
≙-sym xs ys xs≙ys n = sym (xs≙ys n)
≙-trans : ∀ xs ys zs → xs ≙ ys → ys ≙ zs → xs ≙ zs
≙-trans xs ys zs xs≙ys ys≙zs n = trans (xs≙ys n) (ys≙zs n)
≙-isEquivalance : IsEquivalence _≙_
≙-isEquivalance = record
{ refl = λ {xs} → ≙-refl xs
; sym = λ {xs} {ys} → ≙-sym xs ys
; trans = λ {xs} {ys} {zs} → ≙-trans xs ys zs
}
≙-isPreorder : IsPreorder _≙_ _≙_
≙-isPreorder = record
{ isEquivalence = ≙-isEquivalance
; reflexive = id
; trans = λ {xs} {ys} {zs} → ≙-trans xs ys zs
}
≙-Preorder : Preorder _ _ _
≙-Preorder = record
{ Carrier = List ℕ
; _≈_ = _≙_
; _∼_ = _≙_
; isPreorder = ≙-isPreorder
}
≙-∷ : ∀ z {xs ys} → xs ≙ ys → z ∷ xs ≙ z ∷ ys
≙-∷ z xs≙ys n with n ≟ z
≙-∷ z xs≙ys n | yes _ = cong succ (xs≙ys n)
≙-∷ z xs≙ys n | no _ = xs≙ys n
≙-perm : ∀ n₁ n₂ {xs} {ys} → xs ≙ ys → n₁ ∷ n₂ ∷ xs ≙ n₂ ∷ n₁ ∷ ys
≙-perm n₁ n₂ h n with n ≟ n₁ | n ≟ n₂
≙-perm .n₂ n₂ h .n₂ | yes refl | yes refl = cong succ (≙-∷ n₂ h n₂)
≙-perm n₁ n₂ h .n₁ | yes refl | no ¬p with n₁ ≟ n₂
≙-perm n₂ _ h .n₂ | yes refl | no ¬p | yes p = ⊥-elim (¬p p)
≙-perm n₂ _ h .n₂ | yes refl | no ¬p' | no ¬p with n₂ ≟ n₂
≙-perm n₂ _ h .n₂ | yes refl | no ¬p' | no ¬p | yes refl = cong succ (h n₂)
≙-perm n₂ _ h .n₂ | yes refl | no ¬p0 | no ¬p' | no ¬p = ⊥-elim (¬p refl)
≙-perm n₁ n₂ h .n₂ | no ¬p | yes refl with n₂ ≟ n₂
≙-perm n₂ n₃ h ._ | no ¬p | yes refl | yes refl with n₃ ≟ n₂
≙-perm n₃ _ h ._ | no ¬p | yes refl | yes refl | yes p = ⊥-elim (¬p p)
≙-perm n₃ n₄ h ._ | no ¬p' | yes refl | yes refl | no ¬p = cong succ (h n₄)
≙-perm n₂ _ h ._ | no ¬p' | yes refl | no ¬p = ⊥-elim (¬p refl)
≙-perm n₁ n₂ h n | no ¬p | no ¬p' with n ≟ n₂
≙-perm n₁ n₂ h .n₂ | no ¬p | no ¬p' | yes refl = ⊥-elim (¬p' refl)
≙-perm n₁ n₂ h n | no ¬p' | no ¬p0 | no ¬p with n ≟ n₁
≙-perm n₁ n₂ h .n₁ | no ¬p' | no ¬p0 | no ¬p | yes refl = ⊥-elim (¬p' refl)
≙-perm n₁ n₂ h n | no ¬p0 | no ¬p1 | no ¬p' | no ¬p = h n
insertSortedHelper : ∀ {n} {x} {xs} →
x ≤ n →
Sorted (x ∷ xs) →
Sorted (insert n xs) →
Sorted (x ∷ insert n xs)
insertSortedHelper {n} {x} {[]} h₁ h₂ h₃ = sorted-∷ h₁ (sorted-x n)
insertSortedHelper {n} {x} {x' ∷ xs} h₁ h₂ h₃ with n ≤? x'
... | yes p = sorted-∷ h₁ h₃
insertSortedHelper {n} {x} {x' ∷ xs} h₁ (sorted-∷ x≤x' h₂) h₃ | no ¬p =
sorted-∷ x≤x' h₃
insertSorted : ∀ {xs} n → Sorted xs → Sorted (insert n xs)
insertSorted {[]} n s = sorted-x n
insertSorted {(x ∷ xs)} n s with n ≤? x
... | yes p = sorted-∷ p s
... | no ¬p = insertSortedHelper (¬x≤y→y≤x ¬p) s (insertSorted n (tailSorted s))
insert-≙ : ∀ xs n → insert n xs ≙ n ∷ xs
insert-≙ [] n = λ _ → refl
insert-≙ (x ∷ xs) n with n ≤? x
... | yes p = λ _ → refl
... | no ¬p = prf
where
prf : x ∷ insert n xs ≙ n ∷ x ∷ xs
prf =
begin
x ∷ insert n xs ≈⟨ ≙-∷ x (insert-≙ xs n) ⟩
x ∷ n ∷ xs ≈⟨ ≙-perm x n (≙-refl xs) ⟩
n ∷ x ∷ xs
∎
where open Pre ≙-Preorder
sortS : (xs : List ℕ) → Σ (List ℕ) (λ ys → Sorted ys × xs ≙ ys)
sortS [] = [] , sorted-[] , (λ _ → refl)
sortS (x ∷ xs) = l , l-Sorted , x∷xs≡l
where
xs' : List ℕ
xs' = proj₁ $ sortS xs
xs'-Sorted : Sorted xs'
xs'-Sorted = proj₁ $ proj₂ $ sortS xs
xs≙xs' : xs ≙ xs'
xs≙xs' = proj₂ $ proj₂ $ sortS xs
l : List ℕ
l = insert x xs'
l-Sorted : Sorted l
l-Sorted = insertSorted x xs'-Sorted
x∷xs≙x∷xs' : x ∷ xs ≙ x ∷ xs'
x∷xs≙x∷xs' = ≙-∷ x xs≙xs'
x∷xs'≙l : x ∷ xs' ≙ l
x∷xs'≙l = ≙-sym l (x ∷ xs') (insert-≙ xs' x)
x∷xs≡l : x ∷ xs ≙ l
x∷xs≡l = ≙-trans (x ∷ xs) (x ∷ xs') l x∷xs≙x∷xs' x∷xs'≙l
l₁ : List ℕ
l₁ = []
l₂ : List ℕ
l₂ = 1 ∷ 2 ∷ 3 ∷ 4 ∷ 5 ∷ []
l₃ : List ℕ
l₃ = 5 ∷ 4 ∷ 3 ∷ 2 ∷ 1 ∷ []
l₄ : List ℕ
l₄ = 4 ∷ 1 ∷ 3 ∷ 5 ∷ 2 ∷ []