-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/LRAT/Internal/Formula/RupAddSound.lean
theorem confirmRupHint_preserves_motive {n : Nat} (f : DefaultFormula n) (rupHints : Array Nat)
    (idx : Fin rupHints.size) (acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool)
    (ih : ConfirmRupHintFoldEntailsMotive f idx.1 acc) :
    ConfirmRupHintFoldEntailsMotive f (idx.1 + 1) ((confirmRupHint f.clauses) acc rupHints[idx])

Proof state:
case isFalse
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
⊢ p ⊨ acc.fst.modify l.val (addAssignment b)

Tactic:
have pacc := h1 p pf

Result:
case isFalse
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
pacc : p ⊨ acc.fst
⊢ p ⊨ acc.fst.modify l.val (addAssignment b)

Proof state:
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
pc : p ⊨ c
plb : p ⊨ (l, b)
i : PosFin n
i_in_bounds : i.val < acc.fst.size
l_eq_i : l.val = i.val
pacc : hasAssignment (decide (p i = false)) acc.fst[i.val] = false
⊢ hasAssignment (decide (p i = false)) (addAssignment b acc.fst[i.val]) = false

Tactic:
by_cases pi : p i

Result:
case pos
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
pc : p ⊨ c
plb : p ⊨ (l, b)
i : PosFin n
i_in_bounds : i.val < acc.fst.size
l_eq_i : l.val = i.val
pacc : hasAssignment (decide (p i = false)) acc.fst[i.val] = false
pi : p i = true
⊢ hasAssignment (decide (p i = false)) (addAssignment b acc.fst[i.val]) = false

case neg
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
pc : p ⊨ c
plb : p ⊨ (l, b)
i : PosFin n
i_in_bounds : i.val < acc.fst.size
l_eq_i : l.val = i.val
pacc : hasAssignment (decide (p i = false)) acc.fst[i.val] = false
pi : ¬p i = true
⊢ hasAssignment (decide (p i = false)) (addAssignment b acc.fst[i.val]) = false

Proof state:
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
pc : p ⊨ c
plb : p ⊨ (l, b)
i : PosFin n
pacc : hasAssignment (decide (p i = false)) acc.fst[i.val]! = false
i_in_bounds : i.val < acc.fst.size
l_ne_i : ¬l.val = i.val
⊢ hasAssignment (decide (p i = false)) (acc.fst.modify l.val (addAssignment b))[i.val]! = false

Tactic:
simp only [getElem!, Array.size_modify, i_in_bounds,
  Array.getElem_modify_of_ne l_ne_i, dite_true,
  Array.get_eq_getElem, decidableGetElem?]

Result:
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
pc : p ⊨ c
plb : p ⊨ (l, b)
i : PosFin n
pacc : hasAssignment (decide (p i = false)) acc.fst[i.val]! = false
i_in_bounds : i.val < acc.fst.size
l_ne_i : ¬l.val = i.val
⊢ hasAssignment (decide (p i = false)) acc.fst[i.val] = false

Proof state:
case neg
n : Nat
f : DefaultFormula n
rupHints : Array Nat
idx : Fin rupHints.size
acc : Array Assignment × CNF.Clause (PosFin n) × Bool × Bool
hsize : acc.fst.size = n
h1 : Limplies (PosFin n) f acc.fst
h2 : acc.snd.snd.fst = true → Incompatible (PosFin n) acc.fst f
acc2_eq_false : acc.2.2.snd = false ∧ acc.2.2.fst = false
x✝¹ : Option (Option (DefaultClause n))
c : DefaultClause n
hc : f.clauses[rupHints[↑idx]]? = some (some c)
c_in_f : c ∈ f.toList
x✝ : ReduceResult (PosFin n)
l : PosFin n
b : Bool
heq : c.reduce acc.fst = reducedToUnit (l, b)
h✝¹ : ¬hasAssignment b acc.fst[l.val]! = true
p : PosFin n → Bool
pf : p ⊨ f
pc : p ⊨ c
plb : p ⊨ (l, b)
i : PosFin n
pacc : hasAssignment (decide (p i = false)) acc.fst[i.val]! = false
i_in_bounds : i.val < acc.fst.size
h✝ : ¬l.val = i.val
⊢ hasAssignment (decide (p i = false)) (acc.fst.modify l.val (addAssignment b))[i.val]! = false

Tactic:
next l_ne_i =>
simp only [getElem!, Array.size_modify, i_in_bounds,
  Array.getElem_modify_of_ne l_ne_i, dite_true,
  Array.get_eq_getElem, decidableGetElem?]
simp only [getElem!, i_in_bounds, dite_true, decidableGetElem?] at pacc
exact pacc

Result:
no goals