Skip to content

Proved sorted permutations are equal #2748

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

MatthewDaggitt
Copy link
Contributor

The main result. Would like to try and sneak this into v2.3 for @onestruggler.

Have also added an explanation of the choice of propositional permutation in SortingAlgorithm and a lemma that proves the setoid version.

Comment on lines +1065 to +1088
injective⇒nonStrictlyContractive : (f : Fin n Fin m) Injective _≡_ _≡_ f
i ¬ ( j j ≤ i f j < i)
injective⇒nonStrictlyContractive f f-injective i j≤i⇒fj<i =
ℕ.n≮n (toℕ i) (injective⇒≤ h-injective)
where
h : Fin′ (suc i) Fin′ i
h k = lower (f (inject! k)) (j≤i⇒fj<i _ (ℕ.s≤s⁻¹ (inject!-< k)))

h-injective : Injective _≡_ _≡_ h
h-injective = inject!-injective ∘ f-injective ∘ lower-injective _ _

injective⇒existsPivot : (f : Fin n Fin m) Injective _≡_ _≡_ f
(i : Fin n) λ (j : Fin n) j ≤ i × i ≤ f j
injective⇒existsPivot {n = suc n} f f-injective i with any? (λ j j ≤? i ×-dec i ≤? f j)
... | yes result = result
... | no ¬result = contradiction
strictlyContractive
(injective⇒nonStrictlyContractive f f-injective i)
where
strictlyContractive : j j ≤ i f j < i
strictlyContractive j j≤i with i ≤? f j
... | yes i≤fj = contradiction (j , j≤i , i≤fj) ¬result
... | no i≰fj = ℕ.≰⇒> i≰fj

Copy link
Contributor

@jamesmckinna jamesmckinna Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Downstream, after resolving the issues around #2744, I'd hope that these could be read off from a single appeal to min? to construct a suitable minimal counterexample (for existsPivot) or else rule out the Universal case branch by contradiction with nonStrictlyContractive. See also #2746 for the use of pigeonhole to prove injective⇒≤, so some simplification in the proof of nonStrictlyContractive might also be possible?

Copy link
Contributor

@jamesmckinna jamesmckinna Jun 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Voil`a:

Suggested change
injective⇒nonStrictlyContractive : (f : Fin n Fin m) Injective _≡_ _≡_ f →
i ¬ ( j j ≤ i f j < i)
injective⇒nonStrictlyContractive f f-injective i j≤i⇒fj<i =
ℕ.n≮n (toℕ i) (injective⇒≤ h-injective)
where
h : Fin′ (suc i) Fin′ i
h k = lower (f (inject! k)) (j≤i⇒fj<i _ (ℕ.s≤s⁻¹ (inject!-< k)))
h-injective : Injective _≡_ _≡_ h
h-injective = inject!-injective ∘ f-injective ∘ lower-injective _ _
injective⇒existsPivot : (f : Fin n Fin m) Injective _≡_ _≡_ f →
(i : Fin n) λ (j : Fin n) j ≤ i × i ≤ f j
injective⇒existsPivot {n = suc n} f f-injective i with any? (λ j j ≤? i ×-dec i ≤? f j)
... | yes result = result
... | no ¬result = contradiction
strictlyContractive
(injective⇒nonStrictlyContractive f f-injective i)
where
strictlyContractive : j j ≤ i f j < i
strictlyContractive j j≤i with i ≤? f j
... | yes i≤fj = contradiction (j , j≤i , i≤fj) ¬result
... | no i≰fj = ℕ.≰⇒> i≰fj
injective⇒existsPivot : {f : Fin n Fin m} Injective _≡_ _≡_ f →
(i : Fin n) ∃[ j ] j ≤ i × i ≤ f j
injective⇒existsPivot {n = suc n} {f = f} f-injective i
with any? (λ j j ≤? i ×-dec i ≤? f j)
... | yes result = result
... | no ¬result = contradiction (injective⇒≤ h-injective) ℕ.1+n≰n
where
fj<i : (j : Fin′ (suc i)) f (inject! j) < i
fj<i j with f (inject! j) <? i
... | yes fj<i = fj<i
... | no fj≮i = contradiction (_ , ℕ.s≤s⁻¹ (inject!-< j) , ℕ.≮⇒≥ fj≮i) ¬result
h : Fin′ (suc i) Fin′ i
h j = lower (f (inject! j)) (fj<i j)
h-injective : Injective _≡_ _≡_ h
h-injective = inject!-injective ∘ f-injective ∘ lower-injective _ _
injective⇒nonStrictlyContractive : {f : Fin n Fin m} Injective _≡_ _≡_ f →
i ¬ ( j j ≤ i f j < i)
injective⇒nonStrictlyContractive f-injective i j≤i⇒fj<i =
let j , j≤i , i≤fj = injective⇒existsPivot f-injective i
in contradiction (j≤i⇒fj<i j j≤i) (ℕ.≤⇒≯ i≤fj)

I argue as follows:

  • injective⇒nonStrictlyContractive, which I leave in here for API faithfulness, probably doesn't even need to be in the PR, as it now arises an 'easy' consequence by contradiction from the much more interesting (positive!) statement injective⇒existsPivot
  • the proof that you do offer of this latter has some very weird contortions/convolutions via all kinds of contradictions, when the function h, and the proof that it is Injective, at the heart of the main argument, actually becomes considerably simpler once it suffices to define it, towards the eventual contradiction, only within the scope of ¬result... whence the fj<i lemma becomes provable outright.

NB. f can now be implicitly quantified? (and: is!)

@@ -121,6 +121,10 @@ lower₁ {zero} zero ne = contradiction refl ne
lower₁ {suc n} zero _ = zero
lower₁ {suc n} (suc i) ne = suc (lower₁ i (ne ∘ cong suc))

lower : (i : Fin m) .(toℕ i ℕ.< n) Fin n
Copy link
Contributor

@jamesmckinna jamesmckinna Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As on previous iterations: suggest deprecating/redefining lower₁ in terms of this new definition, to avoid redundant duplication?

UPDATED: oh, I see... it would involve importing Data.Nat.Properties in order to fix up the precondition, and that might be considered A Bad Thing...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accordingly, we should perhaps instead consider (an issue about) refactoring to deprecate it, and rewrite (a lot of!?) code which uses it...

∀ {i j} → toℕ i ≡ toℕ j →
lookup ys j ≤ lookup xs i
↗↭↗⇒≤ {xs} {ys} xs↭ys xs↗ ys↗ {i} {j} i≡j
with Fin.injective⇒existsPivot _ (inverseʳ⇒injective _ (Inverse.inverseʳ (toFin xs↭ys))) i
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
with Fin.injective⇒existsPivot _ (inverseʳ⇒injective _ (Inverse.inverseʳ (toFin xs↭ys))) i
with Fin.injective⇒existsPivot _ (inverseʳ⇒injective _ (Inverse.inverseʳ (onIndices xs↭ys))) i

???

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, there's no need for with here: the pattern is irrefutable, and computable with a pattern-matching let, so...

with Fin.injective⇒existsPivot _ (inverseʳ⇒injective _ (Inverse.inverseʳ (toFin xs↭ys))) i
... | (k , k≤i , i≤π[k]) = begin
lookup ys j ≤⟨ lookup-mono-≤ O ys↗ (P.subst (ℕ._≤ _) i≡j i≤π[k]) ⟩
lookup ys (toFin xs↭ys ⟨$⟩ʳ k) ≈⟨ toFin-lookup xs↭ys k ⟨
Copy link
Contributor

@jamesmckinna jamesmckinna Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Suggested change
lookup ys (toFin xs↭ys ⟨$⟩ʳ k) ≈⟨ toFin-lookup xs↭ys k ⟨
lookup ys (onIndices xs↭ys ⟨$⟩ʳ k) ≈⟨ onIndices-lookup xs↭ys k ⟨

Copy link
Contributor

@jamesmckinna jamesmckinna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Various nitpicks and bugfixes suggested, but otherwise: good to go!

Comment on lines +125 to +126
lower {suc _} {suc n} zero leq = zero
lower {suc _} {suc n} (suc i) leq = suc (lower i (ℕ.s≤s⁻¹ leq))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
lower {suc _} {suc n} zero leq = zero
lower {suc _} {suc n} (suc i) leq = suc (lower i (ℕ.s≤s⁻¹ leq))
lower {n = suc _} zero leq = zero
lower {n = suc _} (suc i) leq = suc (lower i (ℕ.s≤s⁻¹ leq))

I don't think there's any need to involve the m binding in the definition, and named telescopes are (typically) more robust in the face of modifications to variable declarations etc.

Comment on lines +560 to +561
lower-injective {suc _} {suc n} zero zero eq = refl
lower-injective {suc _} {suc n} (suc i) (suc j) eq =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto re: avoiding the m binding

Suggested change
lower-injective {suc _} {suc n} zero zero eq = refl
lower-injective {suc _} {suc n} (suc i) (suc j) eq =
lower-injective {n = suc n} zero zero eq = refl
lower-injective {n = suc n} (suc i) (suc j) eq =

```

* In `Data.Fin.Permutation`:
```agda
cast-id : .(m ≡ n) → Permutation m n
swap : Permutation m n → Permutation (suc (suc m)) (suc (suc n))
inject!-injective : swap : Permutation m n → Permutation (suc (suc m)) (suc (suc n))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an entirely separate thing: 2+ ?

Copy link
Contributor

@JacquesCarette JacquesCarette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no comments beyond James'.

```

* In `Data.Fin.Permutation`:
```agda
cast-id : .(m ≡ n) → Permutation m n
swap : Permutation m n → Permutation (suc (suc m)) (suc (suc n))
inject!-injective : swap : Permutation m n → Permutation (suc (suc m)) (suc (suc n))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an entirely separate thing: 2+ ?

-- lower
------------------------------------------------------------------------

lower-injective : {m n} (i j : Fin m)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
lower-injective : {m n} (i j : Fin m)
lower-injective : (i j : Fin m)

m and n are already governed by the top-level variable declarations.

Copy link
Contributor

@jamesmckinna jamesmckinna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to go back on my original approval, but I think the new proof structure is... better!?

Comment on lines +1065 to +1088
injective⇒nonStrictlyContractive : (f : Fin n Fin m) Injective _≡_ _≡_ f
i ¬ ( j j ≤ i f j < i)
injective⇒nonStrictlyContractive f f-injective i j≤i⇒fj<i =
ℕ.n≮n (toℕ i) (injective⇒≤ h-injective)
where
h : Fin′ (suc i) Fin′ i
h k = lower (f (inject! k)) (j≤i⇒fj<i _ (ℕ.s≤s⁻¹ (inject!-< k)))

h-injective : Injective _≡_ _≡_ h
h-injective = inject!-injective ∘ f-injective ∘ lower-injective _ _

injective⇒existsPivot : (f : Fin n Fin m) Injective _≡_ _≡_ f
(i : Fin n) λ (j : Fin n) j ≤ i × i ≤ f j
injective⇒existsPivot {n = suc n} f f-injective i with any? (λ j j ≤? i ×-dec i ≤? f j)
... | yes result = result
... | no ¬result = contradiction
strictlyContractive
(injective⇒nonStrictlyContractive f f-injective i)
where
strictlyContractive : j j ≤ i f j < i
strictlyContractive j j≤i with i ≤? f j
... | yes i≤fj = contradiction (j , j≤i , i≤fj) ¬result
... | no i≰fj = ℕ.≰⇒> i≰fj

Copy link
Contributor

@jamesmckinna jamesmckinna Jun 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Voil`a:

Suggested change
injective⇒nonStrictlyContractive : (f : Fin n Fin m) Injective _≡_ _≡_ f →
i ¬ ( j j ≤ i f j < i)
injective⇒nonStrictlyContractive f f-injective i j≤i⇒fj<i =
ℕ.n≮n (toℕ i) (injective⇒≤ h-injective)
where
h : Fin′ (suc i) Fin′ i
h k = lower (f (inject! k)) (j≤i⇒fj<i _ (ℕ.s≤s⁻¹ (inject!-< k)))
h-injective : Injective _≡_ _≡_ h
h-injective = inject!-injective ∘ f-injective ∘ lower-injective _ _
injective⇒existsPivot : (f : Fin n Fin m) Injective _≡_ _≡_ f →
(i : Fin n) λ (j : Fin n) j ≤ i × i ≤ f j
injective⇒existsPivot {n = suc n} f f-injective i with any? (λ j j ≤? i ×-dec i ≤? f j)
... | yes result = result
... | no ¬result = contradiction
strictlyContractive
(injective⇒nonStrictlyContractive f f-injective i)
where
strictlyContractive : j j ≤ i f j < i
strictlyContractive j j≤i with i ≤? f j
... | yes i≤fj = contradiction (j , j≤i , i≤fj) ¬result
... | no i≰fj = ℕ.≰⇒> i≰fj
injective⇒existsPivot : {f : Fin n Fin m} Injective _≡_ _≡_ f →
(i : Fin n) ∃[ j ] j ≤ i × i ≤ f j
injective⇒existsPivot {n = suc n} {f = f} f-injective i
with any? (λ j j ≤? i ×-dec i ≤? f j)
... | yes result = result
... | no ¬result = contradiction (injective⇒≤ h-injective) ℕ.1+n≰n
where
fj<i : (j : Fin′ (suc i)) f (inject! j) < i
fj<i j with f (inject! j) <? i
... | yes fj<i = fj<i
... | no fj≮i = contradiction (_ , ℕ.s≤s⁻¹ (inject!-< j) , ℕ.≮⇒≥ fj≮i) ¬result
h : Fin′ (suc i) Fin′ i
h j = lower (f (inject! j)) (fj<i j)
h-injective : Injective _≡_ _≡_ h
h-injective = inject!-injective ∘ f-injective ∘ lower-injective _ _
injective⇒nonStrictlyContractive : {f : Fin n Fin m} Injective _≡_ _≡_ f →
i ¬ ( j j ≤ i f j < i)
injective⇒nonStrictlyContractive f-injective i j≤i⇒fj<i =
let j , j≤i , i≤fj = injective⇒existsPivot f-injective i
in contradiction (j≤i⇒fj<i j j≤i) (ℕ.≤⇒≯ i≤fj)

I argue as follows:

  • injective⇒nonStrictlyContractive, which I leave in here for API faithfulness, probably doesn't even need to be in the PR, as it now arises an 'easy' consequence by contradiction from the much more interesting (positive!) statement injective⇒existsPivot
  • the proof that you do offer of this latter has some very weird contortions/convolutions via all kinds of contradictions, when the function h, and the proof that it is Injective, at the heart of the main argument, actually becomes considerably simpler once it suffices to define it, towards the eventual contradiction, only within the scope of ¬result... whence the fj<i lemma becomes provable outright.

NB. f can now be implicitly quantified? (and: is!)

inject!-injective : Injective _≡_ _≡_ inject!
inject!-< : (k : Fin′ i) → inject! k < i
lower-injective : lower i i<n ≡ lower j j<n → i ≡ j
injective⇒nonStrictlyContractive : ∀ (f : Fin n → Fin m) → Injective _≡_ _≡_ f → ∀ i → ¬ (∀ j → j ≤ i → f j < i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest leaving this out of the PR: as below, it's an easy corollary of injective⇒existsPivot after re-ordering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants