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 

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)
i : Fin (Array.size self.arr)
h : ↑i ≠ ↑x
⊢ parent i = ↑(UFModel.parent 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; 

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)
i : Fin (Array.size self.arr)
h : ↑i ≠ ↑x
⊢ ↑(if ↑x = ↑i then y else UFModel.parent m i) = ↑(UFModel.parent m i)

Next tactic:
rw [if_neg h.symm]
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 

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)
x✝ : ↑x < Array.size self.arr
⊢ { parent := ↑y, value := nx.value, rank := nx.rank }.parent = parent { val := ↑x, isLt := x✝ }

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)
    

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
⊢ UFModel.Models arr₂
    (UFModel.setParentBump m x y (_ : UFModel.rank m ↑x ≤ UFModel.rank m ↑y) (_ : ↑(UFModel.parent m y) = ↑y))

Next tactic:
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
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
      

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
⊢ UFModel.Agrees arr₂ (fun x => x.parent) parent

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; 

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
⊢ 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.parent) fun i => ↑(if ↑x = ↑i then y else UFModel.parent 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
      · 

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
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.parent) fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)

Next tactic:
exact this.set (fun i h ↦ by simp [h.symm]) (fun h ↦ by simp [ne, hm.parent_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 

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
h✝ : self.arr[↑x].rank = self.arr[↑y].rank
i : Fin n
h : ↑i ≠ ↑{ val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }
⊢ ↑(if ↑x = ↑i then y else UFModel.parent m i) = parent i

Next tactic:
simp [h.symm]
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 

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
h✝ : self.arr[↑x].rank = self.arr[↑y].rank
h : ↑{ val := ↑y, isLt := (_ : ↑y < Array.size arr₁) } < n
⊢ { parent := self.arr[↑y].parent, value := self.arr[↑y].value, rank := self.arr[↑y].rank + 1 }.parent =
    ↑(if ↑x = ↑{ val := ↑{ val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }, isLt := h } then y
      else UFModel.parent m { val := ↑{ val := ↑y, isLt := (_ : ↑y < Array.size arr₁) }, isLt := h })

Next tactic:
simp [ne, hm.parent_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'])
      · 

Proof state:
case inr
α : 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
h✝ : ¬self.arr[↑x].rank = self.arr[↑y].rank
⊢ UFModel.Agrees (Array.set self.arr x { parent := ↑y, value := self.arr[↑x].value, rank := self.arr[↑x].rank })
    (fun x => x.parent) fun i => ↑(if ↑x = ↑i then y else UFModel.parent m i)

Next tactic:
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
    

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
⊢ UFModel.Models arr₂
    (UFModel.setParentBump m x y (_ : UFModel.rank m ↑x ≤ UFModel.rank m ↑y) (_ : ↑(UFModel.parent m y) = ↑y))

Next tactic:
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])