l3lab/ntp-mathlib huggingface dataset:
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      

Proof state:
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
i : ℕ
h : get? ys i = some (applyId (zip xs ys) y)
hx : ∃ (h : i < length xs), List.get xs { val := i, isLt := h } = x
j : ℕ
hy : get? xs j = some y
h₂ : length xs = length ys
⊢ i < length xs

Next tactic:
cases' hx with hx hx'
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      

Proof state:
case intro
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
i : ℕ
h : get? ys i = some (applyId (zip xs ys) y)
j : ℕ
hy : get? xs j = some y
h₂ : length xs = length ys
hx : i < length xs
hx' : List.get xs { val := i, isLt := hx } = x
⊢ i < length xs

Next tactic:
exact hx
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · 

Proof state:
case neg
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : x ∈ xs
hy : y ∉ xs
⊢ x = y

Next tactic:
rw [← applyId_mem_iff h₀ h₁] at hx hy
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    

Proof state:
case neg
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : applyId (zip xs ys) x ∈ ys
hy : applyId (zip xs ys) y ∉ ys
⊢ x = y

Next tactic:
rw [h] at hx
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    

Proof state:
case neg
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : applyId (zip xs ys) y ∈ ys
hy : applyId (zip xs ys) y ∉ ys
⊢ x = y

Next tactic:
contradiction
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · 

Proof state:
case pos
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : x ∉ xs
hy : y ∈ xs
⊢ x = y

Next tactic:
rw [← applyId_mem_iff h₀ h₁] at hx hy
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    

Proof state:
case pos
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : applyId (zip xs ys) x ∉ ys
hy : applyId (zip xs ys) y ∈ ys
⊢ x = y

Next tactic:
rw [h] at hx
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    

Proof state:
case pos
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : applyId (zip xs ys) y ∉ ys
hy : applyId (zip xs ys) y ∈ ys
⊢ x = y

Next tactic:
contradiction
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · 

Proof state:
case neg
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : x ∉ xs
hy : y ∉ xs
⊢ x = y

Next tactic:
rwa [List.applyId_eq_self, List.applyId_eq_self] at h
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · rwa [List.applyId_eq_self, List.applyId_eq_self] at h <;> 

Proof state:
case neg.a
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : x = applyId (zip xs ys) y
hx : x ∉ xs
hy : y ∉ xs
⊢ y ∉ xs

Next tactic:
assumption
theorem applyId_injective [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) :
    Injective.{u + 1, u + 1} (List.applyId (xs.zip ys)) := by
  intro x y h
  by_cases hx : x ∈ xs <;> by_cases hy : y ∈ xs
  · rw [List.mem_iff_get?] at hx hy
    cases' hx with i hx
    cases' hy with j hy
    suffices some x = some y by injection this
    have h₂ := h₁.length_eq
    rw [List.applyId_zip_eq h₀ h₂ _ _ _ hx] at h
    rw [← hx, ← hy]; congr
    apply List.get?_injective _ (h₁.nodup_iff.1 h₀)
    · symm; rw [h]
      rw [← List.applyId_zip_eq] <;> assumption
    · rw [← h₁.length_eq]
      rw [List.get?_eq_some] at hx
      cases' hx with hx hx'
      exact hx
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · rw [← applyId_mem_iff h₀ h₁] at hx hy
    rw [h] at hx
    contradiction
  · rwa [List.applyId_eq_self, List.applyId_eq_self] at h <;> 

Proof state:
case neg.a
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs ys : List α
h₀ : Nodup xs
h₁ : xs ~ ys
x y : α
h : applyId (zip xs ys) x = applyId (zip xs ys) y
hx : x ∉ xs
hy : y ∉ xs
⊢ x ∉ xs

Next tactic:
assumption
/-- A lazy list, in decreasing order, of sizes that should be
sliced off a list of length `n`
-/
def sliceSizes : ℕ → LazyList ℕ+
  | n =>
    if h : 0 < n then
      have : n / 2 < n := Nat.div_lt_self h (by 

Proof state:
α : Type u
β : Type v
γ : Sort w
x✝ : ℕ
n : ℕ := x✝
h : 0 < n
⊢ 1 < 2

Next tactic:
decide
/-- Shrink an injective function slicing a segment in the middle of the domain and removing
the corresponding elements in the codomain, hence maintaining the property that
one is a permutation of the other.
-/
protected def shrink {α : Type} [DecidableEq α] :
    InjectiveFunction α → List (InjectiveFunction α)
  | ⟨xs, h₀, h₁⟩ => do
    let ⟨xs', ys', h₀, h₁⟩ ← InjectiveFunction.shrinkPerm ⟨_, _, h₀, h₁⟩
    have h₃ : xs'.length ≤ ys'.length := le_of_eq (List.Perm.length_eq h₀)
    have h₄ : ys'.length ≤ xs'.length := le_of_eq (List.Perm.length_eq h₀.symm)
    pure
      ⟨(List.zip xs' ys').map Prod.toSigma,
        by 

Proof state:
α✝ : Type u
β : Type v
γ : Sort w
α : Type
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
h₀✝ : map Sigma.fst xs ~ map Sigma.snd xs
h₁✝ : Nodup (map Sigma.snd xs)
xs' ys' : List α
h₀ : xs' ~ ys'
h₁ : Nodup ys'
h₃ : length xs' ≤ length ys'
h₄ : length ys' ≤ length xs'
⊢ map Sigma.fst (map Prod.toSigma (zip xs' ys')) ~ map Sigma.snd (map Prod.toSigma (zip xs' ys'))

Next tactic:
simp only [comp, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma,
          Prod.snd_toSigma, List.map_map]
/-- Shrink an injective function slicing a segment in the middle of the domain and removing
the corresponding elements in the codomain, hence maintaining the property that
one is a permutation of the other.
-/
protected def shrink {α : Type} [DecidableEq α] :
    InjectiveFunction α → List (InjectiveFunction α)
  | ⟨xs, h₀, h₁⟩ => do
    let ⟨xs', ys', h₀, h₁⟩ ← InjectiveFunction.shrinkPerm ⟨_, _, h₀, h₁⟩
    have h₃ : xs'.length ≤ ys'.length := le_of_eq (List.Perm.length_eq h₀)
    have h₄ : ys'.length ≤ xs'.length := le_of_eq (List.Perm.length_eq h₀.symm)
    pure
      ⟨(List.zip xs' ys').map Prod.toSigma,
        by simp only [comp, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma,
          Prod.snd_toSigma, List.map_map],
        by 

Proof state:
α✝ : Type u
β : Type v
γ : Sort w
α : Type
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
h₀✝ : map Sigma.fst xs ~ map Sigma.snd xs
h₁✝ : Nodup (map Sigma.snd xs)
xs' ys' : List α
h₀ : xs' ~ ys'
h₁ : Nodup ys'
h₃ : length xs' ≤ length ys'
h₄ : length ys' ≤ length xs'
⊢ Nodup (map Sigma.snd (map Prod.toSigma (zip xs' ys')))

Next tactic:
simp only [comp, List.map_snd_zip, *, Prod.snd_toSigma, List.map_map]
/-- Create an injective function from one list and a permutation of that list. -/
protected def mk (xs ys : List α) (h : xs ~ ys) (h' : ys.Nodup) : InjectiveFunction α :=
  have h₀ : xs.length ≤ ys.length := le_of_eq h.length_eq
  have h₁ : ys.length ≤ xs.length := le_of_eq h.length_eq.symm
  InjectiveFunction.mapToSelf (List.toFinmap' (xs.zip ys))
    (by
      

Proof state:
α : Type u
β : Type v
γ : Sort w
xs ys : List α
h : xs ~ ys
h' : Nodup ys
h₀ : length xs ≤ length ys
h₁ : length ys ≤ length xs
⊢ map Sigma.fst (List.toFinmap' (zip xs ys)) ~ map Sigma.snd (List.toFinmap' (zip xs ys))

Next tactic:
simp only [List.toFinmap', comp, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma,
        Prod.snd_toSigma, List.map_map]
/-- Create an injective function from one list and a permutation of that list. -/
protected def mk (xs ys : List α) (h : xs ~ ys) (h' : ys.Nodup) : InjectiveFunction α :=
  have h₀ : xs.length ≤ ys.length := le_of_eq h.length_eq
  have h₁ : ys.length ≤ xs.length := le_of_eq h.length_eq.symm
  InjectiveFunction.mapToSelf (List.toFinmap' (xs.zip ys))
    (by
      simp only [List.toFinmap', comp, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma,
        Prod.snd_toSigma, List.map_map])
    (by 

Proof state:
α : Type u
β : Type v
γ : Sort w
xs ys : List α
h : xs ~ ys
h' : Nodup ys
h₀ : length xs ≤ length ys
h₁ : length ys ≤ length xs
⊢ Nodup (map Sigma.snd (List.toFinmap' (zip xs ys)))

Next tactic:
simp only [List.toFinmap', comp, List.map_snd_zip, *, Prod.snd_toSigma, List.map_map]
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  

Proof state:
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
f : InjectiveFunction α
⊢ Injective (apply f)

Next tactic:
cases' f with xs hperm hnodup
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  

Proof state:
case mapToSelf
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
hperm : map Sigma.fst xs ~ map Sigma.snd xs
hnodup : Nodup (map Sigma.snd xs)
⊢ Injective (apply (mapToSelf xs hperm hnodup))

Next tactic:
generalize h₀ : List.map Sigma.fst xs = xs₀
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  

Proof state:
case mapToSelf
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
hperm : map Sigma.fst xs ~ map Sigma.snd xs
hnodup : Nodup (map Sigma.snd xs)
xs₀ : List α
h₀ : map Sigma.fst xs = xs₀
⊢ Injective (apply (mapToSelf xs hperm hnodup))

Next tactic:
generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  

Proof state:
case mapToSelf
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
hperm : map Sigma.fst xs ~ map Sigma.snd xs
hnodup : Nodup (map Sigma.snd xs)
xs₀ : List α
h₀ : map Sigma.fst xs = xs₀
xs₁ : List α
h₁ : map (id Sigma.snd) xs = xs₁
⊢ Injective (apply (mapToSelf xs hperm hnodup))

Next tactic:
dsimp [id] at h₁
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  

Proof state:
case mapToSelf
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
hperm : map Sigma.fst xs ~ map Sigma.snd xs
hnodup : Nodup (map Sigma.snd xs)
xs₀ : List α
h₀ : map Sigma.fst xs = xs₀
xs₁ : List α
h₁ : map Sigma.snd xs = xs₁
⊢ Injective (apply (mapToSelf xs hperm hnodup))

Next tactic:
have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    rw [← h₀, ← h₁, List.toFinmap']; clear h₀ h₁ xs₀ xs₁ hperm hnodup
    induction xs with
    | nil => simp only [List.zip_nil_right, List.map_nil]
    | cons xs_hd xs_tl xs_ih =>
      simp only [true_and_iff, Prod.toSigma, eq_self_iff_true, Sigma.eta, List.zip_cons_cons,
        List.map, List.cons_inj]
      exact xs_ih
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    

Proof state:
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
hperm : map Sigma.fst xs ~ map Sigma.snd xs
hnodup : Nodup (map Sigma.snd xs)
xs₀ : List α
h₀ : map Sigma.fst xs = xs₀
xs₁ : List α
h₁ : map Sigma.snd xs = xs₁
⊢ xs = List.toFinmap' (zip xs₀ xs₁)

Next tactic:
rw [← h₀, ← h₁, List.toFinmap']
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    rw [← h₀, ← h₁, List.toFinmap']; 

Proof state:
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
hperm : map Sigma.fst xs ~ map Sigma.snd xs
hnodup : Nodup (map Sigma.snd xs)
xs₀ : List α
h₀ : map Sigma.fst xs = xs₀
xs₁ : List α
h₁ : map Sigma.snd xs = xs₁
⊢ xs = map Prod.toSigma (zip (map Sigma.fst xs) (map Sigma.snd xs))

Next tactic:
clear h₀ h₁ xs₀ xs₁ hperm hnodup
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    rw [← h₀, ← h₁, List.toFinmap']; clear h₀ h₁ xs₀ xs₁ hperm hnodup
    

Proof state:
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs : List ((_ : α) × α)
⊢ xs = map Prod.toSigma (zip (map Sigma.fst xs) (map Sigma.snd xs))

Next tactic:
induction xs with
    | nil => simp only [List.zip_nil_right, List.map_nil]
    | cons xs_hd xs_tl xs_ih =>
      simp only [true_and_iff, Prod.toSigma, eq_self_iff_true, Sigma.eta, List.zip_cons_cons,
        List.map, List.cons_inj]
      exact xs_ih
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    rw [← h₀, ← h₁, List.toFinmap']; clear h₀ h₁ xs₀ xs₁ hperm hnodup
    induction xs with
    

Proof state:
case nil
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
⊢ [] = map Prod.toSigma (zip (map Sigma.fst []) (map Sigma.snd []))

Next tactic:
| nil => simp only [List.zip_nil_right, List.map_nil]
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    rw [← h₀, ← h₁, List.toFinmap']; clear h₀ h₁ xs₀ xs₁ hperm hnodup
    induction xs with
    | nil => 

Proof state:
case nil
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
⊢ [] = map Prod.toSigma (zip (map Sigma.fst []) (map Sigma.snd []))

Next tactic:
simp only [List.zip_nil_right, List.map_nil]
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    rw [← h₀, ← h₁, List.toFinmap']; clear h₀ h₁ xs₀ xs₁ hperm hnodup
    induction xs with
    | nil => simp only [List.zip_nil_right, List.map_nil]
    

Proof state:
case cons
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs_hd : (_ : α) × α
xs_tl : List ((_ : α) × α)
xs_ih : xs_tl = map Prod.toSigma (zip (map Sigma.fst xs_tl) (map Sigma.snd xs_tl))
⊢ xs_hd :: xs_tl = map Prod.toSigma (zip (map Sigma.fst (xs_hd :: xs_tl)) (map Sigma.snd (xs_hd :: xs_tl)))

Next tactic:
| cons xs_hd xs_tl xs_ih =>
      simp only [true_and_iff, Prod.toSigma, eq_self_iff_true, Sigma.eta, List.zip_cons_cons,
        List.map, List.cons_inj]
      exact xs_ih
protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by
  cases' f with xs hperm hnodup
  generalize h₀ : List.map Sigma.fst xs = xs₀
  generalize h₁ : xs.map (@id ((Σ _ : α, α) → α) <| @Sigma.snd α fun _ : α => α) = xs₁
  dsimp [id] at h₁
  have hxs : xs = TotalFunction.List.toFinmap' (xs₀.zip xs₁) := by
    rw [← h₀, ← h₁, List.toFinmap']; clear h₀ h₁ xs₀ xs₁ hperm hnodup
    induction xs with
    | nil => simp only [List.zip_nil_right, List.map_nil]
    | cons xs_hd xs_tl xs_ih =>
      

Proof state:
case cons
α : Type u
β : Type v
γ : Sort w
inst✝ : DecidableEq α
xs_hd : (_ : α) × α
xs_tl : List ((_ : α) × α)
xs_ih : xs_tl = map Prod.toSigma (zip (map Sigma.fst xs_tl) (map Sigma.snd xs_tl))
⊢ xs_hd :: xs_tl = map Prod.toSigma (zip (map Sigma.fst (xs_hd :: xs_tl)) (map Sigma.snd (xs_hd :: xs_tl)))

Next tactic:
simp only [true_and_iff, Prod.toSigma, eq_self_iff_true, Sigma.eta, List.zip_cons_cons,
        List.map, List.cons_inj]