-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/LRAT/Internal/Formula/RatAddSound.lean
theorem sat_of_insertRat {n : Nat} (f : DefaultFormula n)
    (hf : f.ratUnits = #[] ∧ AssignmentsInvariant f) (c : DefaultClause n) (p : PosFin n → Bool)
    (pf : p ⊨ f) :
    (insertRatUnits f (negate c)).2 = true → p ⊨ c

Proof state:
n : Nat
f : DefaultFormula n
hf : f.ratUnits = #[] ∧ f.AssignmentsInvariant
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).2.snd = true
i : PosFin n
hboth : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.ratUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
j1 j2 : Fin (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.size
i_gt_zero : ↑⟨i.val, ⋯⟩ > 0
h1 : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[j1] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, true)
h2 : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[j2] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, false)
left✝¹ : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[↑⟨i.val, ⋯⟩] = both
left✝ : f.assignments[↑⟨i.val, ⋯⟩] = unassigned
right✝ :
  ∀ (k : Fin (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.size),
    k ≠ j1 → k ≠ j2 → (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[k].fst.val ≠ ↑⟨i.val, ⋯⟩
i_true_in_insertUnit_fold : (i, true) ∈ (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.toList
i_rw : i = ⟨i.val, ⋯⟩
⊢ (i, false) ∈ (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.toList

Tactic:
rw [i_rw, ← h2]

Result:
n : Nat
f : DefaultFormula n
hf : f.ratUnits = #[] ∧ f.AssignmentsInvariant
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).2.snd = true
i : PosFin n
hboth : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.ratUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
j1 j2 : Fin (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.size
i_gt_zero : ↑⟨i.val, ⋯⟩ > 0
h1 : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[j1] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, true)
h2 : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[j2] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, false)
left✝¹ : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[↑⟨i.val, ⋯⟩] = both
left✝ : f.assignments[↑⟨i.val, ⋯⟩] = unassigned
right✝ :
  ∀ (k : Fin (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.size),
    k ≠ j1 → k ≠ j2 → (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[k].fst.val ≠ ↑⟨i.val, ⋯⟩
i_true_in_insertUnit_fold : (i, true) ∈ (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.toList
i_rw : i = ⟨i.val, ⋯⟩
⊢ (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[j2] ∈
    (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.toList

Proof state:
case h
n : Nat
f : DefaultFormula n
hf : f.ratUnits = #[] ∧ f.AssignmentsInvariant
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).2.snd = true
i✝ : PosFin n
hboth : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[i✝.val] = both
i_in_bounds : i✝.val < f.assignments.size
i : Fin n
⊢ ∀ (j : Fin f.ratUnits.size), ¬f.ratUnits[↑j].fst.val = ↑i

Tactic:
intro j

Result:
case h
n : Nat
f : DefaultFormula n
hf : f.ratUnits = #[] ∧ f.AssignmentsInvariant
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).2.snd = true
i✝ : PosFin n
hboth : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[i✝.val] = both
i_in_bounds : i✝.val < f.assignments.size
i : Fin n
j : Fin f.ratUnits.size
⊢ ¬f.ratUnits[↑j].fst.val = ↑i

Proof state:
case intro.inr.inr.intro.intro.intro.intro.intro.intro.intro.inl
n : Nat
f : DefaultFormula n
hf : f.ratUnits = #[] ∧ f.AssignmentsInvariant
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).2.snd = true
i : PosFin n
hboth : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.ratUnits f.assignments ⋯
insertUnit_fold_satisfies_invariant :
  let update_res := List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate;
  let_fun update_res_size := ⋯;
  InsertUnitInvariant f.assignments ⋯ update_res.fst update_res.snd.fst update_res_size
j1 j2 : Fin (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.size
i_gt_zero : ↑⟨i.val, ⋯⟩ > 0
h1 : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[j1] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, true)
h2 : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[j2] = (⟨↑⟨i.val, ⋯⟩, ⋯⟩, false)
left✝¹ : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[↑⟨i.val, ⋯⟩] = both
left✝ : f.assignments[↑⟨i.val, ⋯⟩] = unassigned
right✝ :
  ∀ (k : Fin (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst.size),
    k ≠ j1 → k ≠ j2 → (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).fst[k].fst.val ≠ ↑⟨i.val, ⋯⟩
i_true_in_insertUnit_fold✝ :
  (i, true) ∈ (List.foldl insertUnit (#[], f.assignments, false) (List.map Literal.negate c.clause)).fst.toList
i_false_in_insertUnit_fold✝ :
  (i, false) ∈ (List.foldl insertUnit (#[], f.assignments, false) (List.map Literal.negate c.clause)).fst.toList
i_true_in_insertUnit_fold : (i, false) ∈ c.clause
i_false_in_insertUnit_fold : (i, true) ∈ c.clause
i_true_not_in_c : ¬(i, true) ∈ c.toList
⊢ False

Tactic:
exact i_true_not_in_c i_false_in_insertUnit_fold

Result:
no goals

Proof state:
case intro
n : Nat
f : DefaultFormula n
hf : f.ratUnits = #[] ∧ f.AssignmentsInvariant
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).2.snd = true
i : PosFin n
hboth : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
⊢ p ⊨ c

Tactic:
have h0 : InsertUnitInvariant f.assignments hf.2.1 f.ratUnits f.assignments hf.2.1 := by
  intro i
  simp only [Fin.getElem_fin, ne_eq, true_and, Bool.not_eq_true, exists_and_right]
  apply Or.inl
  intro j
  rw [hf.1] at j
  exact Fin.elim0 j

Result:
case intro
n : Nat
f : DefaultFormula n
hf : f.ratUnits = #[] ∧ f.AssignmentsInvariant
c : DefaultClause n
p : PosFin n → Bool
pf : p ⊨ f
insertUnit_fold_success : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).2.snd = true
i : PosFin n
hboth : (List.foldl insertUnit (f.ratUnits, f.assignments, false) c.negate).snd.fst[i.val] = both
i_in_bounds : i.val < f.assignments.size
h0 : InsertUnitInvariant f.assignments ⋯ f.ratUnits f.assignments ⋯
⊢ p ⊨ c