-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/LRAT/Internal/Formula/RupAddSound.lean
theorem sat_of_insertRup {n : Nat} (f : DefaultFormula n) (f_readyForRupAdd : ReadyForRupAdd f) (c : DefaultClause n)
    (p : PosFin n → Bool) (pf : p ⊨ f) :
    (insertRupUnits f (negate c)).2 = true → p ⊨ c

Proof state:
case intro.inr.inl.intro.intro.intro.intro.intro.intro.intro.inr.intro.intro.h
n : Nat
f : DefaultFormula n
f_readyForRupAdd : f.ReadyForRupAdd
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).2.snd = true
false_imp : false = true → ∃ i, f.assignments[i.val] = both
i : PosFin n
hboth : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.rupUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
j : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size
b : Bool
i_gt_zero : ↑⟨i.val, ⋯⟩ > 0
h1 : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[j] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, b)
h2 : both = addAssignment b f.assignments[↑⟨i.val, ⋯⟩]
h3 : ¬hasAssignment b f.assignments[↑⟨i.val, ⋯⟩] = true
h4 :
  ∀ (k : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size),
    k ≠ j → (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[k].fst.val ≠ ↑⟨i.val, ⋯⟩
ib_in_insertUnit_fold : (i, b) ∈ (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.toList
i' : PosFin n
i_true_in_c : (i, true) ∈ c.clause
i'_eq_i : i' = i
b_eq_false : false = b
⊢ (i, true) ∈ Clause.toList c ∧ p i = true

Tactic:
apply And.intro i_true_in_c

Result:
case intro.inr.inl.intro.intro.intro.intro.intro.intro.intro.inr.intro.intro.h
n : Nat
f : DefaultFormula n
f_readyForRupAdd : f.ReadyForRupAdd
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).2.snd = true
false_imp : false = true → ∃ i, f.assignments[i.val] = both
i : PosFin n
hboth : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.rupUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
j : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size
b : Bool
i_gt_zero : ↑⟨i.val, ⋯⟩ > 0
h1 : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[j] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, b)
h2 : both = addAssignment b f.assignments[↑⟨i.val, ⋯⟩]
h3 : ¬hasAssignment b f.assignments[↑⟨i.val, ⋯⟩] = true
h4 :
  ∀ (k : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size),
    k ≠ j → (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[k].fst.val ≠ ↑⟨i.val, ⋯⟩
ib_in_insertUnit_fold : (i, b) ∈ (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.toList
i' : PosFin n
i_true_in_c : (i, true) ∈ c.clause
i'_eq_i : i' = i
b_eq_false : false = b
⊢ p i = true

Proof state:
n : Nat
f : DefaultFormula n
f_readyForRupAdd : f.ReadyForRupAdd
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).2.snd = true
false_imp : false = true → ∃ i, f.assignments[i.val] = both
i : PosFin n
hboth : f.assignments[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.rupUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
h1 :
  (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).snd.fst[↑⟨i.val, ⋯⟩] = f.assignments[↑⟨i.val, ⋯⟩]
h2 :
  ∀ (j : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size),
    (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[j].fst.val ≠ ↑⟨i.val, ⋯⟩
hpos : hasAssignment true f.assignments[i.val] = true
⊢ hasAssignment false f.assignments[i.val] = true

Tactic:
simp only [hboth]

Result:
n : Nat
f : DefaultFormula n
f_readyForRupAdd : f.ReadyForRupAdd
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).2.snd = true
false_imp : false = true → ∃ i, f.assignments[i.val] = both
i : PosFin n
hboth : f.assignments[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.rupUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
h1 :
  (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).snd.fst[↑⟨i.val, ⋯⟩] = f.assignments[↑⟨i.val, ⋯⟩]
h2 :
  ∀ (j : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size),
    (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[j].fst.val ≠ ↑⟨i.val, ⋯⟩
hpos : hasAssignment true f.assignments[i.val] = true
⊢ hasAssignment false both = true

Proof state:
n : Nat
f : DefaultFormula n
f_readyForRupAdd : f.ReadyForRupAdd
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).2.snd = true
false_imp : false = true → ∃ i, f.assignments[i.val] = both
i : PosFin n
hboth : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.rupUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
j : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size
b : Bool
i_gt_zero : ↑⟨i.val, ⋯⟩ > 0
h1 : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[j] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, b)
h3 : ¬hasAssignment b f.assignments[↑⟨i.val, ⋯⟩] = true
h4 :
  ∀ (k : Fin (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.size),
    k ≠ j → (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst[k].fst.val ≠ ↑⟨i.val, ⋯⟩
ib_in_insertUnit_fold : (i, b) ∈ (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).fst.toList
i' : PosFin n
i_true_in_c : (i, true) ∈ c.clause
i'_eq_i : i' = i
b_eq_false : false = b
a✝ : Assignment
heq : f.assignments[i.val] = pos
h2 : both = both
hasPosAssignment_fi : hasAssignment true f.assignments[i.val] = true
p_entails_i : p i = true
⊢ p i = true

Tactic:
exact p_entails_i

Result:
no goals

Proof state:
n : Nat
f : DefaultFormula n
f_readyForRupAdd : f.ReadyForRupAdd
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.rupUnits, f.assignments, false) c.negate).2.snd = true
h : false = true
⊢ ∃ i, f.assignments[i.val] = both

Tactic:
simp at h

Result:
no goals