Zulip Chat Archive

Stream: Is there code for X?

Topic: Defining the opposite order of an existing order


Antoine Chambert-Loir (Jul 08 2024 at 17:54):

docs#WellOrderingRel defines a well order on a given type σ. Because I wish to use the lexicographic order on σ →₀ ℕ, and I need that lexicographic order to be a well order, I need to take the opposite of the one given by docs#WellOrderingRel (which will satisfy docs#WellOrderGT).
The simplest thing I could do, for that, was to write these lines:

import Mathlib.Data.Finsupp.WellFounded

variable (σ : Type*)
local instance : LinearOrder σ where
  le x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).le y x
  lt x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).lt y x
  le_refl x := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).le_refl x
  le_trans x y z p q := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).le_trans z y x q p
  lt_iff_le_not_le x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).lt_iff_le_not_le y x
  le_antisymm x y p q := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).le_antisymm x y q p
  min x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).max y x
  max x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).min y x
  compare x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).compare y x
  le_total x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).le_total y x
  decidableLE x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).decidableLE y x
  decidableEq x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).decidableEq x y
  decidableLT x y := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).decidableLT y x
  min_def x y := by
    simp only [min, LE.le, (WellOrderingRel.isWellOrder.linearOrder (α := σ)).max_def]
  max_def x y := by
    simp only [max, LE.le, (WellOrderingRel.isWellOrder.linearOrder (α := σ)).min_def]
  compare_eq_compareOfLessAndEq x y := by
    have := (WellOrderingRel.isWellOrder.linearOrder (α := σ)).compare_eq_compareOfLessAndEq y x
    unfold compare compareOfLessAndEq at this 
    simp only at this 
    rw [this]
    congr 1
    by_cases h : y = x
    · rw [if_pos h, if_pos h.symm]
    · rw [if_neg h, if_neg (Ne.symm h)]

but probably there is a better thing to do.
(Unfortunately, the docs#OrderDual defines an ordering on σ but called σᵒᵈ, and involves given instances relative to σ, hence I didn't really try to pull it back to σ.)

Edward van de Meent (Jul 08 2024 at 18:07):

it seems to me that this can be done a bit simpler:

variable (σ : Type*)

noncomputable local instance : LinearOrder σ := WellOrderingRel.isWellOrder.linearOrder

Edward van de Meent (Jul 08 2024 at 18:08):

or am i missing the point?

Edward van de Meent (Jul 08 2024 at 18:09):

ah, i see that i am missing the point

Edward van de Meent (Jul 08 2024 at 18:24):

i think this might be what is missing:

import Mathlib.Data.Finsupp.WellFounded

variable (σ : Type*) (r:σ  σ  Prop) [IsWellOrder σ r]

/- define a linear order using `r` such that `r x y` -> `y < x` -/
noncomputable def IsWellOrder.linearOrderSwap : LinearOrder σ :=
  letI : IsStrictTotalOrder σ (Function.swap r) := IsStrictTotalOrder.swap r
  letI := fun x y => Classical.dec ¬r y x
  linearOrderOfSTO (Function.swap r)

Eric Wieser (Jul 08 2024 at 18:35):

I would think you can just use OrderDual here

Antoine Chambert-Loir (Jul 09 2024 at 09:52):

Thanks Edward, this short definition of linearOrderSwap was exactly the missing point.
(The second letI line is not necessary for me, since I start from a LinearOrder which already contains the required decidability instances.)

Antoine Chambert-Loir (Jul 09 2024 at 09:54):

I end up with

variable (σ : Type*)
def LinearOrder.swap (h : LinearOrder σ) : LinearOrder σ :=
  letI : IsStrictTotalOrder σ (Function.swap h.lt) := IsStrictTotalOrder.swap h.lt
  linearOrderOfSTO (Function.swap h.lt)

and, in my proof, the invocation of

    letI : LinearOrder σ := LinearOrder.swap WellOrderingRel.isWellOrder.linearOrder
    letI : WellFoundedGT σ := by
      unfold WellFoundedGT
      suffices IsWellFounded σ fun x y  WellOrderingRel x y by
        exact this
      exact IsWellOrder.toIsWellFounded

Eric Wieser (Jul 09 2024 at 18:18):

I think this works, and has better defeqs?

def LinearOrder.swap (_h : LinearOrder X) : LinearOrder X :=
  inferInstanceAs <| LinearOrder (OrderDual X)

Antoine Chambert-Loir (Jul 09 2024 at 19:27):

It works, thanks! (up to the obvious typo, and lint insists on anonymising the argument h).

Antoine Chambert-Loir (Jul 10 2024 at 04:52):

Thinking about this solution, I would like to understand what happens actually? Imagine we have two docs#LinearOrder on X and we want to combine them in some way

def LinearOrder.swap (h1 h2 : LinearOrder X) : LinearOrder X :=
  sorry

and some action within the sorry uses instances. How will Lean choose h1 over h2?
Or, what if in the context of LinearOrder.swapas above, there were already another LinearOrder X floating around?

Kevin Buzzard (Jul 10 2024 at 05:41):

docs#LinearOrder

Kevin Buzzard (Jul 10 2024 at 05:46):

The moment typeclass inference can find more than one linear order on X, or more generally two instances of a class, then my mental model is that it will just use a random one and you have no control over which one it finds (it might be that there is some internal hashing system and it finds the one with the smallest hash, for example). In situations like this you just have to feed everything explicitly with @ and filling in the instance you want. You can see this occasionally in master, for example (at least in lean 3) this had to be worked around when defining the partial order structure on topological space instances on a type.


Last updated: May 02 2025 at 03:31 UTC