Skip to content

Commit 5bd195e

Browse files
Proved sorted permutations are equal (#2748)
* Proved sorted permutations are equal * Addressed James' and Jacques' feedback * Minor tweaks
1 parent ebe659c commit 5bd195e

File tree

7 files changed

+161
-13
lines changed

7 files changed

+161
-13
lines changed

CHANGELOG.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,17 +257,22 @@ Additions to existing modules
257257
```agda
258258
_≰_ : Rel (Fin n) 0ℓ
259259
_≮_ : Rel (Fin n) 0ℓ
260+
lower : ∀ (i : Fin m) → .(toℕ i ℕ.< n) → Fin n
260261
```
261262

262263
* In `Data.Fin.Permutation`:
263264
```agda
264265
cast-id : .(m ≡ n) → Permutation m n
265-
swap : Permutation m n → Permutation (suc (suc m)) (suc (suc n))
266+
swap : Permutation m n → Permutation (2+ m) (2+ n)
266267
```
267268

268269
* In `Data.Fin.Properties`:
269270
```agda
270-
cast-involutive : .(eq₁ : m ≡ n) .(eq₂ : n ≡ m) → ∀ k → cast eq₁ (cast eq₂ k) ≡ k
271+
cast-involutive : .(eq₁ : m ≡ n) .(eq₂ : n ≡ m) → ∀ k → cast eq₁ (cast eq₂ k) ≡ k
272+
inject!-injective : Injective _≡_ _≡_ inject!
273+
inject!-< : (k : Fin′ i) → inject! k < i
274+
lower-injective : lower i i<n ≡ lower j j<n → i ≡ j
275+
injective⇒existsPivot : ∀ (f : Fin n → Fin m) → Injective _≡_ _≡_ f → ∀ (i : Fin n) → ∃ λ j → j ≤ i × i ≤ f j
271276
```
272277

273278
* In `Data.Fin.Subset`:
@@ -452,6 +457,11 @@ Additions to existing modules
452457
map⁻ : AllPairs R (map f xs) → AllPairs (R on f) xs
453458
```
454459

460+
* In `Data.List.Relation.Unary.Linked`:
461+
```agda
462+
lookup : Transitive R → Linked R xs → Connected R (just x) (head xs) → ∀ i → R x (List.lookup xs i)
463+
```
464+
455465
* In `Data.List.Relation.Unary.Unique.Setoid.Properties`:
456466
```agda
457467
map⁻ : Congruent _≈₁_ _≈₂_ f → Unique R (map f xs) → Unique S xs
@@ -461,3 +471,14 @@ Additions to existing modules
461471
```agda
462472
map⁻ : Unique (map f xs) → Unique xs
463473
```
474+
475+
* In `Data.List.Relation.Unary.Sorted.TotalOrder.Properties`:
476+
```agda
477+
lookup-mono-≤ : Sorted xs → i Fin.≤ j → lookup xs i ≤ lookup xs j
478+
↗↭↗⇒≋ : Sorted xs → Sorted ys → xs ↭ ys → xs ≋ ys
479+
```
480+
481+
* In `Data.List.Sort.Base`:
482+
```agda
483+
SortingAlgorithm.sort-↭ₛ : ∀ xs → sort xs Setoid.↭ xs
484+
```

src/Data/Fin/Base.agda

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ lower₁ {zero} zero ne = contradiction refl ne
121121
lower₁ {suc n} zero _ = zero
122122
lower₁ {suc n} (suc i) ne = suc (lower₁ i (ne ∘ cong suc))
123123

124+
lower : (i : Fin m) .(toℕ i ℕ.< n) Fin n
125+
lower {n = suc n} zero leq = zero
126+
lower {n = suc n} (suc i) leq = suc (lower i (ℕ.s≤s⁻¹ leq))
127+
124128
-- A strengthening injection into the minimal Fin fibre.
125129
strengthen : (i : Fin n) Fin′ (suc i)
126130
strengthen zero = zero

src/Data/Fin/Permutation.agda

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ open import Data.Fin.Properties using (punchInᵢ≢i; punchOut-punchIn;
1515
punchOut-cong; punchOut-cong′; punchIn-punchOut
1616
; _≟_; ¬Fin0; cast-involutive; opposite-involutive)
1717
import Data.Fin.Permutation.Components as PC
18-
open import Data.Nat.Base using (ℕ; suc; zero)
18+
open import Data.Nat.Base using (ℕ; suc; zero; 2+)
1919
open import Data.Product.Base using (_,_; proj₂)
2020
open import Function.Bundles using (_↔_; Injection; Inverse; mk↔ₛ′)
2121
open import Function.Construct.Composition using (_↔-∘_)
@@ -261,7 +261,7 @@ insert {m} {n} i j π = permutation to from inverseˡ′ inverseʳ′
261261
--
262262
-- Note: should be refactored as a special-case when we add the
263263
-- concatenation of two permutations
264-
swap : Permutation m n Permutation (suc (suc m)) (suc (suc n))
264+
swap : Permutation m n Permutation (2+ m) (2+ n)
265265
swap π = transpose 0F 1F ∘ₚ lift₀ (lift₀ π)
266266

267267
------------------------------------------------------------------------

src/Data/Fin/Properties.agda

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,19 @@ i≤inject₁[j]⇒i≤1+j : i ≤ inject₁ j → i ≤ suc j
489489
i≤inject₁[j]⇒i≤1+j {i = zero} _ = z≤n
490490
i≤inject₁[j]⇒i≤1+j {i = suc i} {j = suc j} i≤j = s≤s (ℕ.m≤n⇒m≤1+n (subst (toℕ i ℕ.≤_) (toℕ-inject₁ j) (ℕ.s≤s⁻¹ i≤j)))
491491

492+
------------------------------------------------------------------------
493+
-- inject!
494+
------------------------------------------------------------------------
495+
496+
inject!-injective : {i : Fin (suc n)} Injective _≡_ _≡_ (inject! {i = i})
497+
inject!-injective {n = suc n} {i = suc i} {0F} {0F} refl = refl
498+
inject!-injective {n = suc n} {i = suc i} {suc x} {suc y} eq =
499+
cong suc (inject!-injective (suc-injective eq))
500+
501+
inject!-< : {i : Fin (suc n)} (k : Fin′ i) inject! k < i
502+
inject!-< {suc n} {suc i} 0F = s≤s z≤n
503+
inject!-< {suc n} {suc i} (suc k) = s≤s (inject!-< k)
504+
492505
------------------------------------------------------------------------
493506
-- lower₁
494507
------------------------------------------------------------------------
@@ -537,6 +550,17 @@ inject₁≡⇒lower₁≡ : ∀ {i : Fin n} {j : Fin (ℕ.suc n)} →
537550
(n≢j : n ≢ toℕ j) inject₁ i ≡ j lower₁ j n≢j ≡ i
538551
inject₁≡⇒lower₁≡ n≢j i≡j = inject₁-injective (trans (inject₁-lower₁ _ n≢j) (sym i≡j))
539552

553+
------------------------------------------------------------------------
554+
-- lower
555+
------------------------------------------------------------------------
556+
557+
lower-injective : (i j : Fin m)
558+
.{i<n : toℕ i ℕ.< n} .{j<n : toℕ j ℕ.< n}
559+
lower i i<n ≡ lower j j<n i ≡ j
560+
lower-injective {n = suc n} zero zero eq = refl
561+
lower-injective {n = suc n} (suc i) (suc j) eq =
562+
cong suc (lower-injective i j (suc-injective eq))
563+
540564
------------------------------------------------------------------------
541565
-- inject≤
542566
------------------------------------------------------------------------
@@ -1038,6 +1062,24 @@ cantor-schröder-bernstein : ∀ {f : Fin m → Fin n} {g : Fin n → Fin m} →
10381062
cantor-schröder-bernstein f-inj g-inj = ℕ.≤-antisym
10391063
(injective⇒≤ f-inj) (injective⇒≤ g-inj)
10401064

1065+
injective⇒existsPivot : {f : Fin n Fin m} Injective _≡_ _≡_ f
1066+
(i : Fin n) λ j j ≤ i × i ≤ f j
1067+
injective⇒existsPivot {f = f} f-injective i
1068+
with any? (λ j j ≤? i ×-dec i ≤? f j)
1069+
... | yes result = result
1070+
... | no ¬result = contradiction (injective⇒≤ f∘inject!-injective) ℕ.1+n≰n
1071+
where
1072+
fj<i : (j : Fin′ (suc i)) f (inject! j) < i
1073+
fj<i j with f (inject! j) <? i
1074+
... | yes fj<i = fj<i
1075+
... | no fj≮i = contradiction (_ , ℕ.s≤s⁻¹ (inject!-< j) , ℕ.≮⇒≥ fj≮i) ¬result
1076+
1077+
f∘inject! : Fin′ (suc i) Fin′ i
1078+
f∘inject! j = lower (f (inject! j)) (fj<i j)
1079+
1080+
f∘inject!-injective : Injective _≡_ _≡_ f∘inject!
1081+
f∘inject!-injective = inject!-injective ∘ f-injective ∘ lower-injective _ _
1082+
10411083
------------------------------------------------------------------------
10421084
-- Effectful
10431085
------------------------------------------------------------------------

src/Data/List/Relation/Unary/Linked.agda

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Data.List.Relation.Unary.Linked {a} {A : Set a} where
1111
open import Data.List.Base as List using (List; []; _∷_)
1212
open import Data.List.Relation.Unary.All as All using (All; []; _∷_)
1313
open import Data.Product.Base as Prod using (_,_; _×_; uncurry; <_,_>)
14+
open import Data.Fin.Base using (zero; suc)
1415
open import Data.Maybe.Base using (just)
1516
open import Data.Maybe.Relation.Binary.Connected
1617
using (Connected; just; just-nothing)
@@ -26,6 +27,7 @@ open import Relation.Nullary.Decidable using (yes; no; map′; _×-dec_)
2627
private
2728
variable
2829
p q r ℓ : Level
30+
R : Rel A ℓ
2931

3032
------------------------------------------------------------------------
3133
-- Definition
@@ -92,6 +94,14 @@ module _ {P : Rel A p} {Q : Rel A q} where
9294
unzip : Linked (P ∩ᵇ Q) ⊆ Linked P ∩ᵘ Linked Q
9395
unzip = unzipWith id
9496

97+
lookup : {x xs} Transitive R Linked R xs
98+
Connected R (just x) (List.head xs)
99+
i R x (List.lookup xs i)
100+
lookup trans [-] (just Rvx) zero = Rvx
101+
lookup trans (x ∷ xs↗) (just Rvx) zero = Rvx
102+
lookup trans (x ∷ xs↗) (just Rvx) (suc i) =
103+
lookup trans xs↗ (just (trans Rvx x)) i
104+
95105
------------------------------------------------------------------------
96106
-- Properties of predicates preserved by Linked
97107

src/Data/List/Relation/Unary/Sorted/TotalOrder/Properties.agda

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,34 @@ open import Data.List.Relation.Unary.AllPairs using (AllPairs)
1414
open import Data.List.Relation.Unary.Linked as Linked
1515
using (Linked; []; [-]; _∷_; _∷′_; head′; tail)
1616
import Data.List.Relation.Unary.Linked.Properties as Linked
17+
import Data.List.Relation.Binary.Equality.Setoid as Equality
1718
import Data.List.Relation.Binary.Sublist.Setoid as Sublist
1819
import Data.List.Relation.Binary.Sublist.Setoid.Properties as SublistProperties
19-
open import Data.List.Relation.Unary.Sorted.TotalOrder hiding (head)
20-
20+
import Data.List.Relation.Binary.Permutation.Setoid as Permutation
21+
import Data.List.Relation.Binary.Permutation.Setoid.Properties as PermutationProperties
22+
import Data.List.Relation.Binary.Pointwise as Pointwise
23+
open import Data.List.Relation.Unary.Sorted.TotalOrder as Sorted hiding (head)
24+
25+
open import Data.Fin.Base as Fin hiding (_<_; _≤_)
26+
import Data.Fin.Properties as Fin
27+
open import Data.Fin.Permutation
28+
open import Data.Product using (_,_)
2129
open import Data.Maybe.Base using (just; nothing)
2230
open import Data.Maybe.Relation.Binary.Connected using (Connected; just)
23-
open import Data.Nat.Base using (ℕ; zero; suc; _<_)
24-
31+
open import Data.Nat.Base as ℕ using (ℕ; z≤n; s≤s; zero; suc)
32+
import Data.Nat.Properties as ℕ
33+
open import Function.Base using (_∘_; const)
34+
open import Function.Bundles using (Inverse)
35+
open import Function.Consequences.Propositional using (inverseʳ⇒injective)
2536
open import Level using (Level)
26-
open import Relation.Binary.Core using (_Preserves_⟶_)
37+
open import Relation.Binary.Core using (_Preserves_⟶_; Rel)
2738
open import Relation.Binary.Bundles using (TotalOrder; DecTotalOrder; Preorder)
2839
import Relation.Binary.Properties.TotalOrder as TotalOrderProperties
40+
import Relation.Binary.Reasoning.PartialOrder as PosetReasoning
2941
open import Relation.Unary using (Pred; Decidable)
42+
open import Relation.Nullary using (contradiction)
3043
open import Relation.Nullary.Decidable using (yes; no)
44+
open import Relation.Binary.PropositionalEquality.Core as ≡ using (_≡_)
3145

3246
private
3347
variable
@@ -80,7 +94,7 @@ module _ (O : TotalOrder a ℓ₁ ℓ₂) where
8094
module _ (O : TotalOrder a ℓ₁ ℓ₂) where
8195
open TotalOrder O
8296

83-
applyUpTo⁺₁ : f n ( {i} suc i < n f i ≤ f (suc i))
97+
applyUpTo⁺₁ : f n ( {i} suc i ℕ.< n f i ≤ f (suc i))
8498
Sorted O (applyUpTo f n)
8599
applyUpTo⁺₁ = Linked.applyUpTo⁺₁
86100

@@ -94,7 +108,7 @@ module _ (O : TotalOrder a ℓ₁ ℓ₂) where
94108
module _ (O : TotalOrder a ℓ₁ ℓ₂) where
95109
open TotalOrder O
96110

97-
applyDownFrom⁺₁ : f n ( {i} suc i < n f (suc i) ≤ f i)
111+
applyDownFrom⁺₁ : f n ( {i} suc i ℕ.< n f (suc i) ≤ f i)
98112
Sorted O (applyDownFrom f n)
99113
applyDownFrom⁺₁ = Linked.applyDownFrom⁺₁
100114

@@ -150,3 +164,48 @@ module _ (O : TotalOrder a ℓ₁ ℓ₂) {P : Pred _ p} (P? : Decidable P) wher
150164

151165
filter⁺ : {xs} Sorted O xs Sorted O (filter P? xs)
152166
filter⁺ = Linked.filter⁺ P? trans
167+
168+
------------------------------------------------------------------------
169+
-- lookup
170+
171+
module _ (O : TotalOrder a ℓ₁ ℓ₂) where
172+
open TotalOrder O
173+
174+
lookup-mono-≤ : {xs} Sorted O xs
175+
{i j} i Fin.≤ j lookup xs i ≤ lookup xs j
176+
lookup-mono-≤ {x ∷ xs} xs↗ {zero} {zero} z≤n = refl
177+
lookup-mono-≤ {x ∷ xs} xs↗ {zero} {suc j} z≤n = Linked.lookup trans xs↗ (just refl) (suc j)
178+
lookup-mono-≤ {x ∷ xs} xs↗ {suc i} {suc j} (s≤s i≤j) = lookup-mono-≤ (Sorted.tail O {y = x} xs↗) i≤j
179+
180+
------------------------------------------------------------------------
181+
-- Relationship to binary relations
182+
------------------------------------------------------------------------
183+
184+
module _ (O : TotalOrder a ℓ₁ ℓ₂) where
185+
open TotalOrder O
186+
open Equality Eq.setoid
187+
open Permutation Eq.setoid hiding (refl; trans)
188+
open PermutationProperties Eq.setoid
189+
open PosetReasoning poset
190+
191+
-- Proof that any two sorted lists that are a permutation of each
192+
-- other are pointwise equal
193+
↗↭↗⇒≋ : {xs ys} Sorted O xs Sorted O ys xs ↭ ys xs ≋ ys
194+
↗↭↗⇒≋ {xs} {ys} xs↗ ys↗ xs↭ys = Pointwise.lookup⁻
195+
(xs↭ys⇒|xs|≡|ys| xs↭ys)
196+
(λ i≡j antisym
197+
(↗↭↗⇒≤ (↭-sym xs↭ys) ys↗ xs↗ (≡.sym i≡j))
198+
(↗↭↗⇒≤ xs↭ys xs↗ ys↗ i≡j))
199+
where
200+
↗↭↗⇒≤ : {xs ys}
201+
(xs↭ys : xs ↭ ys)
202+
Sorted O xs Sorted O ys
203+
{i j} toℕ i ≡ toℕ j
204+
lookup ys j ≤ lookup xs i
205+
↗↭↗⇒≤ {xs} {ys} xs↭ys xs↗ ys↗ {i} {j} i≡j
206+
with Fin.injective⇒existsPivot (inverseʳ⇒injective _ (Inverse.inverseʳ (onIndices xs↭ys))) i
207+
... | (k , k≤i , i≤π[k]) = begin
208+
lookup ys j ≤⟨ lookup-mono-≤ O ys↗ (≡.subst (ℕ._≤ _) i≡j i≤π[k]) ⟩
209+
lookup ys (onIndices xs↭ys ⟨$⟩ʳ k) ≈⟨ onIndices-lookup xs↭ys k ⟨
210+
lookup xs k ≤⟨ lookup-mono-≤ O xs↗ k≤i ⟩
211+
lookup xs i ∎

src/Data/List/Sort/Base.agda

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ module Data.List.Sort.Base
1313
where
1414

1515
open import Data.List.Base using (List)
16-
open import Data.List.Relation.Binary.Permutation.Propositional using (_↭_)
16+
open import Data.List.Relation.Binary.Permutation.Propositional
17+
using (_↭_; ↭⇒↭ₛ)
18+
import Data.List.Relation.Binary.Permutation.Homogeneous as Homo
1719
open import Level using (_⊔_)
1820

1921
open TotalOrder totalOrder renaming (Carrier to A)
2022
open import Data.List.Relation.Unary.Sorted.TotalOrder totalOrder
23+
import Data.List.Relation.Binary.Permutation.Setoid Eq.setoid as S
2124

2225
------------------------------------------------------------------------
2326
-- Definition of a sorting algorithm
@@ -26,8 +29,17 @@ record SortingAlgorithm : Set (a ⊔ ℓ₁ ⊔ ℓ₂) where
2629
field
2730
sort : List A List A
2831

29-
-- The output of `sort` is a permutation of the input
32+
-- The output of `sort` is a propositional permutation of the input.
33+
-- Note that the choice of using a propositional equality here
34+
-- is very deliberate. A sorting algorithm should only be capable
35+
-- of altering the order of the elements of the list, and should not
36+
-- be capable of altering the elements themselves in any way.
3037
sort-↭ : xs sort xs ↭ xs
3138

3239
-- The output of `sort` is sorted.
3340
sort-↗ : xs Sorted (sort xs)
41+
42+
-- Lists are also permutations under the setoid versions of
43+
-- permutation.
44+
sort-↭ₛ : xs sort xs S.↭ xs
45+
sort-↭ₛ xs = Homo.map Eq.reflexive (↭⇒↭ₛ (sort-↭ xs))

0 commit comments

Comments
 (0)