l3lab/ntp-mathlib huggingface dataset:
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by 

Proof state:
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
i : Fin (Array.size self.arr)
x✝ : ↑i ≠ ↑x
⊢ UFModel.rank m ↑i = UFModel.rank m ↑i

Next tactic:
simp
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by 

Proof state:
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
x✝ : ↑x < Array.size self.arr
⊢ { parent := ↑y, value := nx.value, rank := nx.rank }.rank = UFModel.rank m ↑{ val := ↑x, isLt := x✝ }

Next tactic:
simp [hm.rank_eq]
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by simp [hm.rank_eq])
    

Proof state:
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this✝ : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
this : UFModel.Agrees arr₁ (fun x => x.rank) fun i => UFModel.rank m ↑i
⊢ UFModel.Models arr₂
    (UFModel.setParentBump m x y (_ : UFModel.rank m ↑x ≤ UFModel.rank m ↑y) (_ : ↑(UFModel.parent m y) = ↑y))

Next tactic:
let rank (i : Fin n) := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by simp [hm.rank_eq])
    let rank (i : Fin n) := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
    

Proof state:
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this✝ : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
this : UFModel.Agrees arr₁ (fun x => x.rank) fun i => UFModel.rank m ↑i
rank : Fin n → ℕ :=
  fun i => if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i
⊢ UFModel.Models arr₂
    (UFModel.setParentBump m x y (_ : UFModel.rank m ↑x ≤ UFModel.rank m ↑y) (_ : ↑(UFModel.parent m y) = ↑y))

Next tactic:
have H2 : UFModel.Agrees arr₂ (·.rank) rank := by
      simp; split <;> (rename_i xy; simp [hm.rank_eq] at xy; simp [xy])
      · exact this.set (fun i h ↦ by rw [if_neg h.symm]) (fun h ↦ by simp [hm.rank_eq])
      · exact this
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by simp [hm.rank_eq])
    let rank (i : Fin n) := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
    have H2 : UFModel.Agrees arr₂ (·.rank) rank := by
      

Proof state:
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this✝ : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
this : UFModel.Agrees arr₁ (fun x => x.rank) fun i => UFModel.rank m ↑i
rank : Fin n → ℕ :=
  fun i => if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i
⊢ UFModel.Agrees arr₂ (fun x => x.rank) rank

Next tactic:
simp
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by simp [hm.rank_eq])
    let rank (i : Fin n) := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
    have H2 : UFModel.Agrees arr₂ (·.rank) rank := by
      simp; 

Proof state:
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this✝ : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
this : UFModel.Agrees arr₁ (fun x => x.rank) fun i => UFModel.rank m ↑i
rank : Fin n → ℕ :=
  fun i => if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i
⊢ UFModel.Agrees
    (if self.arr[↑x].rank = self.arr[↑y].rank then
      Array.set (Array.set self.arr x { parent := ↑y, value := self.arr[↑x].value, rank := self.arr[↑x].rank })
        { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
        { parent := self.arr[↑y].parent, value := self.arr[↑y].value, rank := self.arr[↑y].rank + 1 }
    else Array.set self.arr x { parent := ↑y, value := self.arr[↑x].value, rank := self.arr[↑x].rank })
    (fun x => x.rank) fun i =>
    if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i

Next tactic:
split
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by simp [hm.rank_eq])
    let rank (i : Fin n) := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
    have H2 : UFModel.Agrees arr₂ (·.rank) rank := by
      simp; split <;> (

Proof state:
case inl
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this✝ : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
this : UFModel.Agrees arr₁ (fun x => x.rank) fun i => UFModel.rank m ↑i
rank : Fin n → ℕ :=
  fun i => if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i
h✝ : self.arr[↑x].rank = self.arr[↑y].rank
⊢ UFModel.Agrees
    (Array.set (Array.set self.arr x { parent := ↑y, value := self.arr[↑x].value, rank := self.arr[↑x].rank })
      { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := self.arr[↑y].parent, value := self.arr[↑y].value, rank := self.arr[↑y].rank + 1 })
    (fun x => x.rank) fun i =>
    if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i

Next tactic:
rename_i xy
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by simp [hm.rank_eq])
    let rank (i : Fin n) := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
    have H2 : UFModel.Agrees arr₂ (·.rank) rank := by
      simp; split <;> (rename_i xy; 

Proof state:
case inl
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this✝ : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
this : UFModel.Agrees arr₁ (fun x => x.rank) fun i => UFModel.rank m ↑i
rank : Fin n → ℕ :=
  fun i => if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i
xy : self.arr[↑x].rank = self.arr[↑y].rank
⊢ UFModel.Agrees
    (Array.set (Array.set self.arr x { parent := ↑y, value := self.arr[↑x].value, rank := self.arr[↑x].rank })
      { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := self.arr[↑y].parent, value := self.arr[↑y].value, rank := self.arr[↑y].rank + 1 })
    (fun x => x.rank) fun i =>
    if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i

Next tactic:
simp [hm.rank_eq] at xy
def link (self : UnionFind α) (x y : Fin self.size)
    (yroot : (self.arr.get y).parent = y) : UnionFind α := by
  refine if ne : x.1 = y then self else
    let nx := self.arr[x]
    let ny := self.arr[y]
    if h : ny.rank < nx.rank then
      ⟨self.arr.set y {ny with parent := x}, ?a⟩
    else
      let arr₁ := self.arr.set x {nx with parent := y}
      let arr₂ := if nx.rank = ny.rank then
        arr₁.set ⟨y, by simp; exact y.2⟩ {ny with rank := ny.rank + 1}
      else arr₁
      ⟨arr₂, ?b⟩
  -- start proof
  case a =>
    let ⟨m, hm⟩ := self.model'
    exact ⟨_, _, hm.setParent y x (by simpa [hm.rank_eq] using h) _ _ rfl rfl⟩
  case b =>
    let ⟨m, hm⟩ := self.model'; let n := self.size
    refine ⟨_, m.setParentBump x y (by simpa [hm.rank_eq] using h)
      (by simpa [← hm.parent_eq'] using yroot), ?_⟩
    let parent (i : Fin n) := (if x.1 = i then y else m.parent i).1
    have : UFModel.Agrees arr₁ (·.parent) parent :=
      hm.1.set (fun i h ↦ by simp; rw [if_neg h.symm]) (fun _ ↦ by simp)
    have H1 : UFModel.Agrees arr₂ (·.parent) parent := by
      simp; split
      · exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_eq'])
      · exact this
    have : UFModel.Agrees arr₁ (·.rank) (fun i : Fin n ↦ m.rank i) :=
      hm.2.set (fun i _ ↦ by simp) (fun _ ↦ by simp [hm.rank_eq])
    let rank (i : Fin n) := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
    have H2 : UFModel.Agrees arr₂ (·.rank) rank := by
      simp; split <;> (rename_i xy; simp [hm.rank_eq] at xy; 

Proof state:
case inl
α : Type ?u.85186
self : UnionFind α
x y : Fin (size self)
yroot : (Array.get self.arr y).parent = ↑y
ne : ¬↑x = ↑y
nx : UFNode α := self.arr[x]
ny : UFNode α := self.arr[y]
h : ¬ny.rank < nx.rank
arr₁ : Array (UFNode α) := Array.set self.arr x { parent := ↑y, value := nx.value, rank := nx.rank }
arr₂ : Array (UFNode α) :=
  if nx.rank = ny.rank then
    Array.set arr₁ { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := ny.parent, value := ny.value, rank := ny.rank + 1 }
  else arr₁
m : UFModel (Array.size self.arr)
hm : UFModel.Models self.arr m
n : ℕ := size self
parent : Fin n → ℕ := fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)
this✝ : UFModel.Agrees arr₁ (fun x => x.parent) parent
H1 : UFModel.Agrees arr₂ (fun x => x.parent) parent
this : UFModel.Agrees arr₁ (fun x => x.rank) fun i => UFModel.rank m ↑i
rank : Fin n → ℕ :=
  fun i => if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i
xy : UFModel.rank m ↑x = UFModel.rank m ↑y
⊢ UFModel.Agrees
    (Array.set (Array.set self.arr x { parent := ↑y, value := self.arr[↑x].value, rank := self.arr[↑x].rank })
      { val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
      { parent := self.arr[↑y].parent, value := self.arr[↑y].value, rank := self.arr[↑y].rank + 1 })
    (fun x => x.rank) fun i =>
    if ↑y = ↑i ∧ UFModel.rank m ↑x = UFModel.rank m ↑y then UFModel.rank m ↑y + 1 else UFModel.rank m ↑i

Next tactic:
simp [xy]