-
Notifications
You must be signed in to change notification settings - Fork 257
Insertion sort and its properties. A bug in MergeSort.agda is fixed. #2723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 19 commits
3607a89
1fe5083
4d09168
4a02eb3
c28ca9e
e256297
b352836
af20074
d9c401d
477b9ed
123e1d0
cef93fc
97483fe
2a7923e
11c4c74
319e1c6
bd90301
37e848e
8af98e7
bdf30ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
------------------------------------------------------------------------ | ||
-- The Agda standard library | ||
-- | ||
-- An implementation of insertion sort and its properties | ||
------------------------------------------------------------------------ | ||
|
||
{-# OPTIONS --cubical-compatible --safe #-} | ||
|
||
open import Relation.Binary.Bundles using (DecTotalOrder) | ||
|
||
module Data.List.Sort.InsertionSort | ||
{a ℓ₁ ℓ₂} | ||
(O : DecTotalOrder a ℓ₁ ℓ₂) | ||
where | ||
|
||
open import Data.List.Sort.InsertionSort.Base O public | ||
open import Data.List.Sort.InsertionSort.Properties O using (insertionSort) public |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
------------------------------------------------------------------------ | ||
-- The Agda standard library | ||
-- | ||
-- An implementation of insertion sort | ||
------------------------------------------------------------------------ | ||
|
||
{-# OPTIONS --cubical-compatible --safe #-} | ||
|
||
open import Relation.Binary.Bundles using (DecTotalOrder) | ||
|
||
module Data.List.Sort.InsertionSort.Base | ||
{a ℓ₁ ℓ₂} | ||
(O : DecTotalOrder a ℓ₁ ℓ₂) | ||
where | ||
|
||
open import Data.Bool.Base using (if_then_else_) | ||
open import Data.List.Base using (List; []; _∷_) | ||
open import Relation.Nullary.Decidable.Core using (does) | ||
|
||
open DecTotalOrder O renaming (Carrier to A) | ||
|
||
------------------------------------------------------------------------ | ||
-- Definitions | ||
|
||
insert : A → List A → List A | ||
insert x [] = x ∷ [] | ||
insert x (y ∷ xs) = if does (x ≤? y) | ||
then x ∷ y ∷ xs | ||
else y ∷ insert x xs | ||
|
||
sort : List A → List A | ||
sort [] = [] | ||
sort (x ∷ xs) = insert x (sort xs) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
------------------------------------------------------------------------ | ||
-- The Agda standard library | ||
-- | ||
-- Properties of insertion sort | ||
------------------------------------------------------------------------ | ||
|
||
{-# OPTIONS --cubical-compatible --safe #-} | ||
|
||
open import Relation.Binary.Bundles using (DecTotalOrder) | ||
|
||
module Data.List.Sort.InsertionSort.Properties | ||
{a ℓ₁ ℓ₂} | ||
(O : DecTotalOrder a ℓ₁ ℓ₂) | ||
where | ||
|
||
open import Data.Bool.Base using (true; false; if_then_else_) | ||
open import Data.List.Base using (List; []; _∷_) | ||
open import Data.List.Relation.Unary.Linked using ([]; [-]; _∷_) | ||
open import Data.List.Relation.Binary.Pointwise using ([]; _∷_; decidable; setoid) | ||
open import Relation.Binary.Bundles using (Setoid) | ||
open import Relation.Binary.Definitions using (Decidable) | ||
open import Relation.Binary.Properties.DecTotalOrder O using (≰⇒≥) | ||
open import Relation.Nullary.Decidable.Core using (does; yes; no) | ||
open import Relation.Nullary.Negation.Core using (contradiction) | ||
|
||
open DecTotalOrder O renaming (Carrier to A; trans to ≤-trans) | ||
using (totalOrder; _≤?_; _≤_; module Eq; _≈_; ≤-respʳ-≈; ≤-respˡ-≈; antisym) | ||
|
||
open import Data.List.Relation.Binary.Equality.Setoid Eq.setoid | ||
using (_≋_; ≋-refl; ≋-sym; ≋-trans) | ||
open import Data.List.Relation.Binary.Permutation.Setoid Eq.setoid | ||
open import Data.List.Relation.Unary.Sorted.TotalOrder totalOrder using (Sorted) | ||
open import Data.List.Sort.Base totalOrder using (SortingAlgorithm) | ||
open import Data.List.Sort.InsertionSort.Base O | ||
import Relation.Binary.Reasoning.Setoid (setoid Eq.setoid) as ≋-Reasoning | ||
|
||
------------------------------------------------------------------------ | ||
-- Permutation property | ||
|
||
insert-↭ : ∀ x xs → insert x xs ↭ x ∷ xs | ||
insert-↭ x [] = ↭-refl | ||
insert-↭ x (y ∷ xs) with does (x ≤? y) | ||
... | true = ↭-refl | ||
... | false = begin | ||
y ∷ insert x xs ↭⟨ prep Eq.refl (insert-↭ x xs) ⟩ | ||
y ∷ x ∷ xs ↭⟨ swap Eq.refl Eq.refl ↭-refl ⟩ | ||
x ∷ y ∷ xs ∎ | ||
where open PermutationReasoning | ||
|
||
insert-cong-↭ : ∀ {x xs y ys} → x ≈ y → xs ↭ ys → insert x xs ↭ y ∷ ys | ||
insert-cong-↭ {x} {xs} {y} {ys} eq₁ eq₂ = begin | ||
insert x xs ↭⟨ insert-↭ x xs ⟩ | ||
x ∷ xs ↭⟨ prep eq₁ eq₂ ⟩ | ||
y ∷ ys ∎ | ||
where open PermutationReasoning | ||
|
||
sort-↭ : ∀ (xs : List A) → sort xs ↭ xs | ||
sort-↭ [] = ↭-refl | ||
sort-↭ (x ∷ xs) = insert-cong-↭ Eq.refl (sort-↭ xs) | ||
|
||
------------------------------------------------------------------------ | ||
-- Sorted property | ||
|
||
insert-↗ : ∀ x {xs} → Sorted xs → Sorted (insert x xs) | ||
insert-↗ x [] = [-] | ||
insert-↗ x ([-] {y}) with x ≤? y | ||
... | yes x≤y = x≤y ∷ [-] | ||
... | no x≰y = ≰⇒≥ x≰y ∷ [-] | ||
insert-↗ x (_∷_ {y} {z} {ys} y≤z z≤ys) with x ≤? y | ||
... | yes x≤y = x≤y ∷ y≤z ∷ z≤ys | ||
... | no x≰y with ih ← insert-↗ x z≤ys | x ≤? z | ||
... | yes _ = ≰⇒≥ x≰y ∷ ih | ||
... | no _ = y≤z ∷ ih | ||
|
||
sort-↗ : ∀ xs → Sorted (sort xs) | ||
sort-↗ [] = [] | ||
sort-↗ (x ∷ xs) = insert-↗ x (sort-↗ xs) | ||
|
||
------------------------------------------------------------------------ | ||
-- Algorithm | ||
|
||
insertionSort : SortingAlgorithm | ||
insertionSort = record | ||
{ sort = sort | ||
; sort-↭ = sort-↭ | ||
; sort-↗ = sort-↗ | ||
} | ||
|
||
------------------------------------------------------------------------ | ||
-- Congruence properties | ||
|
||
insert-congʳ : ∀ z {xs ys} → xs ≋ ys → insert z xs ≋ insert z ys | ||
insert-congʳ z [] = ≋-refl | ||
insert-congʳ z (_∷_ {x} {y} {xs} {ys} x∼y eq) with z ≤? x | z ≤? y | ||
... | yes _ | yes _ = Eq.refl ∷ x∼y ∷ eq | ||
... | no z≰x | yes z≤y = contradiction (≤-respʳ-≈ (Eq.sym x∼y) z≤y) z≰x | ||
... | yes z≤x | no z≰y = contradiction (≤-respʳ-≈ x∼y z≤x) z≰y | ||
... | no _ | no _ = x∼y ∷ insert-congʳ z eq | ||
|
||
insert-congˡ : ∀ {x y} xs → x ≈ y → insert x xs ≋ insert y xs | ||
insert-congˡ {x} {y} [] eq = eq ∷ [] | ||
insert-congˡ {x} {y} (z ∷ xs) eq with x ≤? z | y ≤? z | ||
... | yes _ | yes _ = eq ∷ ≋-refl | ||
... | no x≰z | yes y≤z = contradiction (≤-respˡ-≈ (Eq.sym eq) y≤z) x≰z | ||
... | yes x≤z | no y≰z = contradiction (≤-respˡ-≈ eq x≤z) y≰z | ||
... | no _ | no _ = Eq.refl ∷ insert-congˡ xs eq | ||
|
||
insert-cong : ∀ {x y xs ys} → x ≈ y → xs ≋ ys → insert x xs ≋ insert y ys | ||
insert-cong {y = y} {xs} eq₁ eq₂ = ≋-trans (insert-congˡ xs eq₁) (insert-congʳ y eq₂) | ||
|
||
sort-cong : ∀ {xs ys} → xs ≋ ys → sort xs ≋ sort ys | ||
sort-cong [] = [] | ||
sort-cong (x∼y ∷ eq) = insert-cong x∼y (sort-cong eq) | ||
|
||
insert-swap-≤ : ∀ {x y} xs → x ≤ y → insert x (insert y xs) ≋ insert y (insert x xs) | ||
insert-swap-≤ {x} {y} [] x≤y with x ≤? y | ||
... | no xy = contradiction x≤y xy | ||
... | yes xy with y ≤? x | ||
... | yes yx = Eq.sym eq ∷ eq ∷ [] where eq = antisym yx xy | ||
... | no _ = ≋-refl | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y with y ≤? z | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz with x ≤? y | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | yes xy with x ≤? z | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | yes xy | yes xz with y ≤? x | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | yes xy | yes xz | yes yx = | ||
Eq.sym eq ∷ eq ∷ ≋-refl where eq = antisym yx xy | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | yes xy | yes xz | no yx with y ≤? z | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | yes xy | yes xz | no yx | yes yz' = ≋-refl | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | yes xy | yes xz | no yx | no yz' = contradiction yz yz' | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | yes xy | no xz = contradiction (≤-trans xy yz) xz | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | yes yz | no xy = contradiction x≤y xy | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz with x ≤? z | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | yes xz with y ≤? x | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | yes xz | yes yx = contradiction (≤-trans yx xz) yz | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | yes xz | no yx with y ≤? z | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | yes xz | no yx | yes yz' = contradiction yz' yz | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | yes xz | no yx | no yz' = ≋-refl | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | no xz with y ≤? z | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | no xz | yes yz' = contradiction yz' yz | ||
insert-swap-≤ {x} {y} (z ∷ xs) x≤y | no yz | no xz | no yz' = Eq.refl ∷ (insert-swap-≤ xs x≤y) | ||
|
||
insert-swap : ∀ x y xs → insert x (insert y xs) ≋ insert y (insert x xs) | ||
insert-swap x y xs with x ≤? y | ||
... | yes x≤y = insert-swap-≤ xs x≤y | ||
... | no x≰y = ≋-sym (insert-swap-≤ xs (≰⇒≥ x≰y)) | ||
|
||
insert-swap-cong : ∀ {x y x′ y′ xs ys} → x ≈ x′ → y ≈ y′ → xs ≋ ys → | ||
insert x (insert y xs) ≋ insert y′ (insert x′ ys) | ||
insert-swap-cong {x} {y} {x′} {y′} {xs} {ys} eq₁ eq₂ eq₃ = begin | ||
insert x (insert y xs) ≈⟨ insert-cong eq₁ (insert-cong eq₂ eq₃) ⟩ | ||
insert x′ (insert y′ ys) ≈⟨ insert-swap x′ y′ ys ⟩ | ||
insert y′ (insert x′ ys) ∎ | ||
where open ≋-Reasoning | ||
|
||
-- Ideally, we want: | ||
|
||
-- property1 : ∀ {xs ys} → xs ↭ ys → Sorted xs → Sorted ys → xs ≋ ys | ||
|
||
-- But the induction over xs ↭ ys is hard to do for the "transitive" | ||
-- constructor. So instead we have a similar property that depends on | ||
-- the particular sorting algorithm used. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As you say in the comment, this isn't really the form of the two lemmas we want to prove. Yes, the transitive constructor makes the proof hard, but its not impossible to do. I'd really prefer to have the correct lemma in the library, rather than the "wrong" one that we have to go to the faff of removing later... If the full lemma is too hard to prove, then I suggest we simply remove these two lemmas. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have tried to prove the full lemma using the current permutation definition, but failed. Issue #2311 started one year ago was trying to fix the definition, but not ready yet. Ignore the comment for a moment, the property sort-cong-↭ is just a congruence for sort, which itself as a property for sort should be there, but it is implied by the full lemma. Can we change the proof of sort-cong-↭ later and keep this property now? I also have subsequent developement depending on the decidability of permutation. If not, I have no problem removing them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @onestruggler I've proved the general lemma ↗↭↗⇒≋ : ∀ {xs ys} → Sorted O xs → Sorted O ys → xs ↭ ys → xs ≋ ys in the branch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "property1 : ∀ {xs ys} → xs ~ ys → Sorted xs → Sorted ys → xs ≋ ys" is still hard to prove using the new definition in #2726 . Induction over ⋎ cannot go through, becasue I need "b ∷ cs" to be sorted in order to call IH on it. It is unreasonable to ask "b ∷ cs" to be sorted. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you squint at the following line in the new def of permuation in #2726 ⋎ : as ∼ b ∷ cs → a ∷ cs ∼ bs → a ∷ as ∼ b ∷ bs this line is essentially transitivity (plus swap): as ~ cs -> cs ~ bs -> as ~ bs. The reason we cannot get rid of transitivity is that transitivity is composition of permutations. We cannot list all N! permutations in our inductive data type, we can only choose some generators, e.g. right now all swaps (transpositions) (we know transpositions generates all permuations) , so we have to compose generators to get all permutations. So transitivity is non-elimable. So induction proof can never avoid transivity, hence hard to go through. This suggests the "full lemma" as called by Matt is hard to prove using whatever defs of permutations. Hence the not-so-full lemma depending on a particular sorting algorithm seems the only way to do it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, I am going to make a new PR later. Your proof is impressive! Thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @onestruggler thanks for the comments on #2726 suggest we move the discussion there? But yes, the merge constructor indeed incorporates some transitivity, but in a more constrained way, moreover list There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @jamesmckinna , sure, let's move to #2726 after this post. Matt has a proof that avoids induction over transitivity, so different defs for permutation is no longer urgent for proving the "full lemma". But simple defs is definitely preferable. |
||
|
||
sort-cong-↭ : ∀ {xs ys} → xs ↭ ys → sort xs ≋ sort ys | ||
sort-cong-↭ (refl x) = sort-cong x | ||
sort-cong-↭ (prep eq eq₁) = insert-cong eq (sort-cong-↭ eq₁) | ||
sort-cong-↭ (swap eq₁ eq₂ eq) = insert-swap-cong eq₁ eq₂ (sort-cong-↭ eq) | ||
sort-cong-↭ (trans eq eq₁) = ≋-trans (sort-cong-↭ eq) (sort-cong-↭ eq₁) | ||
|
||
------------------------------------------------------------------------ | ||
-- Decidability property | ||
|
||
infix 4 _↭?_ | ||
|
||
_↭?_ : Decidable _↭_ | ||
xs ↭? ys with decidable Eq._≟_ (sort xs) (sort ys) | ||
... | yes eq = yes (begin | ||
xs ↭⟨ sort-↭ xs ⟨ | ||
sort xs ↭⟨ refl eq ⟩ | ||
sort ys ↭⟨ sort-↭ ys ⟩ | ||
ys ∎) | ||
where open PermutationReasoning | ||
... | no neq = no (λ x → neq (sort-cong-↭ x)) |
Uh oh!
There was an error while loading. Please reload this page.