Zulip Chat Archive

Stream: Is there code for X?

Topic: obtaining an index permutation from a `List.Perm`?


Kim Morrison (Apr 13 2025 at 02:32):

I'd like the following

def idx [BEq α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (i : Nat) : Nat := ...

theorem getElem?_idx [BEq α] [LawfulBEq α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (i : Nat) :
    l₁[h.idx i]? = l₂[i]? := by sorry

allowing index-based arguments about permutations. Do we have this, or something functionally equivalent, somewhere?

Kim Morrison (Apr 13 2025 at 02:34):

One approach I considered was

def idxAux [BEq α] (l₁ : List (Bool × α)) (l₂ : List α) (i : Nat) : Option Nat :=
  match i, l₂ with
  | 0, [] => some 0
  | 0, x :: _ => l₁.idxOf? (true, x)
  | i + 1, [] => some (i + 1)
  | i + 1, x :: l₂ => idxAux (l₁ := l₁.replace (true, x) (false, x)) (l₂ := l₂) i

def idx [BEq α] [LawfulBEq α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (i : Nat) : Nat :=
  (idxAux (l₁.map ((true, ·))) l₂ i).get sorry

but the proofs seemed pretty annoying.

Kim Morrison (Apr 13 2025 at 02:35):

(auxiliary theorems, such as getting the inverse function from h.symm, optional :-)

Markus Himmel (Apr 13 2025 at 08:43):

If you don't need it to be computable, then here is one way to get started:

open List

-- Like `List.Perm` but data
inductive List.Perm' {α : Type u} : List α  List α  Type u where
  | nil : [].Perm' []
  | cons (x : α) {l₁ l₂ : List α} : Perm' l₁ l₂  Perm' (x :: l₁) (x :: l₂ )
  | swap (x y : α) (l : List α) : Perm' (y :: x :: l) (x :: y :: l)
  | trans {l₁ l₂ l₃} : Perm' l₁ l₂  Perm' l₂ l₃  Perm' l₁ l₃

theorem List.Perm'.perm : {l₁ l₂ : List α}  Perm' l₁ l₂  l₁ ~ l₂
  | _, _, nil => Perm.nil
  | _, _, cons x p => Perm.cons x p.perm
  | _, _, swap x y l => Perm.swap x y l
  | _, _, trans p q => Perm.trans p.perm q.perm

theorem List.Perm.perm' {l₁ l₂ : List α} (h : l₁ ~ l₂) : Nonempty (Perm' l₁ l₂) := by
  induction h with
  | nil => exact Perm'.nil
  | cons _ _ p =>
    rcases p with pp
    exact Perm'.cons _ pp
  | swap => exact Perm'.swap _ _ _
  | trans _ _ p q =>
    rcases p with pp
    rcases q with qq
    exact Perm'.trans pp qq

def List.Perm'.idx : {l₁ l₂ : List α}  Perm' l₁ l₂  Nat  Nat
  | _, _, nil, n => n
  | _, _, cons x p, n => if n = 0 then 0 else p.idx (n - 1) + 1
  | _, _, swap x y l, n => if n = 0 then 1 else if n = 1 then 0 else n
  | _, _, trans p q, n => p.idx (q.idx n)

theorem List.Perm'.getElem?_idx : {l₁ l₂ : List α}  (h : Perm' l₁ l₂)  (i : Nat)  l₁[h.idx i]? = l₂[i]?
  | _, _, nil, i => by simp
  | _, _, cons x p, i => by
    rw [idx]
    split
    · simp_all
    · rw [getElem?_cons_succ, getElem?_idx]
      rw (occs := [2]) [(show i = (i - 1) + 1 by omega)]
      rw [getElem?_cons_succ]
  | _, _, swap x y l, i => by
    rw [idx]
    split <;> (try split)
    · simp_all
    · simp_all
    · rw [(show i = (i - 2) + 2 by omega)]
      simp only [getElem?_cons_succ]
  | _, _, trans p q, i => by rw [idx, p.getElem?_idx, q.getElem?_idx]

noncomputable def List.Perm.idx {l₁ l₂ : List α} (h : l₁ ~ l₂) (i : Nat) : Nat :=
  (Classical.choice h.perm').idx i

theorem List.Perm.getElem?_idx {l₁ l₂ : List α} (h : l₁ ~ l₂) (i : Nat) :
    l₁[h.idx i]? = l₂[i]? := by
  rw [idx, List.Perm'.getElem?_idx]

I think this recovers your approach if instead of any permutation you pick the lexicographically smallest one.


Last updated: May 02 2025 at 03:31 UTC