-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/LRAT/Internal/Formula/RupAddResult.lean
theorem confirmRupHint_preserves_invariant_helper {n : Nat} (f : DefaultFormula n)
    (f_assignments_size : f.assignments.size = n)
    (acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool) (hsize : acc.1.size = n)
    (l : Literal (PosFin n)) (ih : DerivedLitsInvariant f f_assignments_size acc.1 hsize acc.2.1)
    (h : ¬hasAssignment l.snd acc.fst[l.fst.val]! = true) :
    have hsize' : (Array.modify acc.1 l.1.1 (addAssignment l.snd)).size = n

Proof state:
case right.right.left
n : Nat
f : DefaultFormula n
f_assignments_size : f.assignments.size = n
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
l : Literal (PosFin n)
ih : f.DerivedLitsInvariant f_assignments_size acc.fst hsize acc.snd.fst
h : ¬hasAssignment l.snd acc.fst[l.fst.val]! = true
hsize'✝ : (acc.fst.modify l.fst.val (addAssignment l.snd)).size = n :=
  Eq.mpr (id (congrArg (fun _a => _a = n) (Array.size_modify acc.fst l.fst.val (addAssignment l.snd)))) hsize
i : Fin n
i_in_bounds : ↑i < acc.fst.size
l_in_bounds : l.fst.val < acc.fst.size
h1 : acc.fst[↑i] = f.assignments[↑i]
h2 : ∀ (l : Literal (PosFin n)), l ∈ acc.snd.fst → l.fst.val ≠ ↑i
l_eq_i : l.fst.val = ↑i
zero_lt_length_list : 0 < (l :: acc.snd.fst).length
⊢ hasAssignment l.snd f.assignments[↑i] = false

Tactic:
simp only [getElem!, l_in_bounds, ↓reduceDIte, Array.get_eq_getElem,
  Bool.not_eq_true, decidableGetElem?] at h

Result:
case right.right.left
n : Nat
f : DefaultFormula n
f_assignments_size : f.assignments.size = n
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
l : Literal (PosFin n)
ih : f.DerivedLitsInvariant f_assignments_size acc.fst hsize acc.snd.fst
hsize'✝ : (acc.fst.modify l.fst.val (addAssignment l.snd)).size = n :=
  Eq.mpr (id (congrArg (fun _a => _a = n) (Array.size_modify acc.fst l.fst.val (addAssignment l.snd)))) hsize
i : Fin n
i_in_bounds : ↑i < acc.fst.size
l_in_bounds : l.fst.val < acc.fst.size
h1 : acc.fst[↑i] = f.assignments[↑i]
h2 : ∀ (l : Literal (PosFin n)), l ∈ acc.snd.fst → l.fst.val ≠ ↑i
l_eq_i : l.fst.val = ↑i
zero_lt_length_list : 0 < (l :: acc.snd.fst).length
h : hasAssignment l.snd acc.fst[l.fst.val] = false
⊢ hasAssignment l.snd f.assignments[↑i] = false

Proof state:
case right.right.right.right
n : Nat
f : DefaultFormula n
f_assignments_size : f.assignments.size = n
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
l : Literal (PosFin n)
ih : f.DerivedLitsInvariant f_assignments_size acc.fst hsize acc.snd.fst
h : ¬hasAssignment l.snd acc.fst[l.fst.val]! = true
hsize'✝ : (acc.fst.modify l.fst.val (addAssignment l.snd)).size = n :=
  Eq.mpr (id (congrArg (fun _a => _a = n) (Array.size_modify acc.fst l.fst.val (addAssignment l.snd)))) hsize
i : Fin n
i_in_bounds : ↑i < acc.fst.size
l_in_bounds : l.fst.val < acc.fst.size
j : Fin (List.length acc.snd.fst)
j_eq_i : (List.get acc.snd.fst j).fst.val = ↑i
h1 : acc.fst[↑i] = addAssignment (List.get acc.snd.fst j).snd f.assignments[↑i]
h2 : ¬hasAssignment (List.get acc.snd.fst j).snd f.assignments[↑i] = true
h3 : ∀ (k : Fin (List.length acc.snd.fst)), k ≠ j → (List.get acc.snd.fst k).fst.val ≠ ↑i
l' : Literal (PosFin n) := List.get acc.snd.fst j
zero_in_bounds : 0 < (l :: acc.snd.fst).length
j_succ_in_bounds : ↑j + 1 < (l :: acc.snd.fst).length
l_eq_i : l.fst.val = ↑i
l_ne_l' : true ≠ l'.snd
l_eq_true : l.snd = true
l'_eq_false : l'.snd = false
k : Fin (List.length acc.snd.fst + 1)
k_ne_zero : ¬k = ⟨0, zero_in_bounds⟩
k_ne_j_succ : ¬k = ⟨↑j + 1, j_succ_in_bounds⟩
⊢ ¬((l :: acc.snd.fst).get k).fst.val = ↑i

Tactic:
have k_eq_succ : ∃ k' : Nat, ∃ k'_succ_in_bounds : k' + 1 < (l :: acc.2.1).length, k = ⟨k' + 1, k'_succ_in_bounds⟩ := by
  have k_val_ne_zero : k.1 ≠ 0 := by
    intro k_eq_zero
    simp only [List.length_cons, ← k_eq_zero, ne_eq, not_true] at k_ne_zero
  rcases Nat.exists_eq_succ_of_ne_zero k_val_ne_zero with ⟨k', k_eq_k'_succ⟩
  rw [Nat.succ_eq_add_one k'] at k_eq_k'_succ
  have k'_succ_in_bounds : k' + 1 < (l :: acc.2.1).length := by rw [← k_eq_k'_succ]; exact k.2
  apply Exists.intro k' ∘ Exists.intro k'_succ_in_bounds
  apply Fin.eq_of_val_eq
  exact k_eq_k'_succ

Result:
case right.right.right.right
n : Nat
f : DefaultFormula n
f_assignments_size : f.assignments.size = n
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
l : Literal (PosFin n)
ih : f.DerivedLitsInvariant f_assignments_size acc.fst hsize acc.snd.fst
h : ¬hasAssignment l.snd acc.fst[l.fst.val]! = true
hsize'✝ : (acc.fst.modify l.fst.val (addAssignment l.snd)).size = n :=
  Eq.mpr (id (congrArg (fun _a => _a = n) (Array.size_modify acc.fst l.fst.val (addAssignment l.snd)))) hsize
i : Fin n
i_in_bounds : ↑i < acc.fst.size
l_in_bounds : l.fst.val < acc.fst.size
j : Fin (List.length acc.snd.fst)
j_eq_i : (List.get acc.snd.fst j).fst.val = ↑i
h1 : acc.fst[↑i] = addAssignment (List.get acc.snd.fst j).snd f.assignments[↑i]
h2 : ¬hasAssignment (List.get acc.snd.fst j).snd f.assignments[↑i] = true
h3 : ∀ (k : Fin (List.length acc.snd.fst)), k ≠ j → (List.get acc.snd.fst k).fst.val ≠ ↑i
l' : Literal (PosFin n) := List.get acc.snd.fst j
zero_in_bounds : 0 < (l :: acc.snd.fst).length
j_succ_in_bounds : ↑j + 1 < (l :: acc.snd.fst).length
l_eq_i : l.fst.val = ↑i
l_ne_l' : true ≠ l'.snd
l_eq_true : l.snd = true
l'_eq_false : l'.snd = false
k : Fin (List.length acc.snd.fst + 1)
k_ne_zero : ¬k = ⟨0, zero_in_bounds⟩
k_ne_j_succ : ¬k = ⟨↑j + 1, j_succ_in_bounds⟩
k_eq_succ : ∃ k' k'_succ_in_bounds, k = ⟨k' + 1, k'_succ_in_bounds⟩
⊢ ¬((l :: acc.snd.fst).get k).fst.val = ↑i