-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/LRAT/Internal/Formula/RupAddSound.lean
theorem reduce_fold_fn_preserves_induction_motive {c_arr : Array (Literal (PosFin n))}
    {assignment : Array Assignment}
    (idx : Fin c_arr.size) (res : ReduceResult (PosFin n))
    (ih : ReducePostconditionInductionMotive c_arr assignment idx.1 res) :
  ReducePostconditionInductionMotive c_arr assignment (idx.1 + 1) (reduce_fold_fn assignment res c_arr[idx])

Proof state:
case left
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
res : ReduceResult (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) res
h :
  (match res with
    | encounteredBoth => encounteredBoth
    | reducedToEmpty =>
      match assignment[c_arr[↑idx].fst.val]! with
      | pos => if c_arr[↑idx].snd = true then reducedToUnit c_arr[↑idx] else reducedToEmpty
      | neg => if (!c_arr[↑idx].snd) = true then reducedToUnit c_arr[↑idx] else reducedToEmpty
      | both => encounteredBoth
      | unassigned => reducedToUnit c_arr[↑idx]
    | reducedToUnit l' =>
      match assignment[c_arr[↑idx].fst.val]! with
      | pos => if c_arr[↑idx].snd = true then reducedToNonunit else reducedToUnit l'
      | neg => if (!c_arr[↑idx].snd) = true then reducedToNonunit else reducedToUnit l'
      | both => encounteredBoth
      | unassigned => reducedToNonunit
    | reducedToNonunit => reducedToNonunit) =
    reducedToEmpty
p : PosFin n → Bool
⊢ (∀ (i : Fin c_arr.size), ↑i < ↑idx + 1 → ¬(p ⊨ c_arr[↑i])) ∨ ¬(p ⊨ assignment)

Tactic:
split at h

Result:
case left.h_1
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
p : PosFin n → Bool
acc✝ : ReduceResult (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) encounteredBoth
h : encounteredBoth = reducedToEmpty
⊢ (∀ (i : Fin c_arr.size), ↑i < ↑idx + 1 → ¬(p ⊨ c_arr[↑i])) ∨ ¬(p ⊨ assignment)

case left.h_2
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
p : PosFin n → Bool
acc✝ : ReduceResult (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) reducedToEmpty
h :
  (match assignment[c_arr[↑idx].fst.val]! with
    | pos => if c_arr[↑idx].snd = true then reducedToUnit c_arr[↑idx] else reducedToEmpty
    | neg => if (!c_arr[↑idx].snd) = true then reducedToUnit c_arr[↑idx] else reducedToEmpty
    | both => encounteredBoth
    | unassigned => reducedToUnit c_arr[↑idx]) =
    reducedToEmpty
⊢ (∀ (i : Fin c_arr.size), ↑i < ↑idx + 1 → ¬(p ⊨ c_arr[↑i])) ∨ ¬(p ⊨ assignment)

case left.h_3
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
p : PosFin n → Bool
acc✝ : ReduceResult (PosFin n)
l'✝ : Literal (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) (reducedToUnit l'✝)
h :
  (match assignment[c_arr[↑idx].fst.val]! with
    | pos => if c_arr[↑idx].snd = true then reducedToNonunit else reducedToUnit l'✝
    | neg => if (!c_arr[↑idx].snd) = true then reducedToNonunit else reducedToUnit l'✝
    | both => encounteredBoth
    | unassigned => reducedToNonunit) =
    reducedToEmpty
⊢ (∀ (i : Fin c_arr.size), ↑i < ↑idx + 1 → ¬(p ⊨ c_arr[↑i])) ∨ ¬(p ⊨ assignment)

case left.h_4
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
p : PosFin n → Bool
acc✝ : ReduceResult (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) reducedToNonunit
h : reducedToNonunit = reducedToEmpty
⊢ (∀ (i : Fin c_arr.size), ↑i < ↑idx + 1 → ¬(p ⊨ c_arr[↑i])) ∨ ¬(p ⊨ assignment)

Proof state:
case right.h_2.h_4.inl.inl
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
i : PosFin n
b : Bool
p : PosFin n → Bool
hp : p ⊨ assignment
j : Fin c_arr.size
j_lt_idx_add_one : ↑j < ↑idx + 1
p_entails_c_arr_j : p ⊨ c_arr[↑j]
acc✝ : ReduceResult (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) reducedToEmpty
x✝ : Assignment
heq✝ : assignment[c_arr[↑idx].fst.val]! = unassigned
h : c_arr[↑idx] = (i, b)
j_lt_idx : ↑j < ↑idx
ih1 : ∀ (i : Fin c_arr.size), ↑i < ↑idx → ¬(p ⊨ c_arr[i])
⊢ False

Tactic:
exact ih1 j j_lt_idx p_entails_c_arr_j

Result:
no goals

Proof state:
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
i : PosFin n
b : Bool
p : PosFin n → Bool
hp : p ⊨ assignment
j : Fin c_arr.size
j_lt_idx_add_one : ↑j < ↑idx + 1
p_entails_c_arr_j : p ⊨ c_arr[↑j]
acc✝ : ReduceResult (PosFin n)
l : Literal (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) (reducedToUnit l)
h :
  (match assignment[c_arr[↑idx].fst.val]! with
    | pos => if c_arr[↑idx].snd = true then reducedToNonunit else reducedToUnit l
    | neg => if (!c_arr[↑idx].snd) = true then reducedToNonunit else reducedToUnit l
    | both => encounteredBoth
    | unassigned => reducedToNonunit) =
    reducedToUnit (i, b)
⊢ p ⊨ (i, b)

Tactic:
split at h

Result:
case h_1
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
i : PosFin n
b : Bool
p : PosFin n → Bool
hp : p ⊨ assignment
j : Fin c_arr.size
j_lt_idx_add_one : ↑j < ↑idx + 1
p_entails_c_arr_j : p ⊨ c_arr[↑j]
acc✝ : ReduceResult (PosFin n)
l : Literal (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) (reducedToUnit l)
x✝ : Assignment
heq✝ : assignment[c_arr[↑idx].fst.val]! = pos
h : (if c_arr[↑idx].snd = true then reducedToNonunit else reducedToUnit l) = reducedToUnit (i, b)
⊢ p ⊨ (i, b)

case h_2
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
i : PosFin n
b : Bool
p : PosFin n → Bool
hp : p ⊨ assignment
j : Fin c_arr.size
j_lt_idx_add_one : ↑j < ↑idx + 1
p_entails_c_arr_j : p ⊨ c_arr[↑j]
acc✝ : ReduceResult (PosFin n)
l : Literal (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) (reducedToUnit l)
x✝ : Assignment
heq✝ : assignment[c_arr[↑idx].fst.val]! = neg
h : (if (!c_arr[↑idx].snd) = true then reducedToNonunit else reducedToUnit l) = reducedToUnit (i, b)
⊢ p ⊨ (i, b)

case h_3
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
i : PosFin n
b : Bool
p : PosFin n → Bool
hp : p ⊨ assignment
j : Fin c_arr.size
j_lt_idx_add_one : ↑j < ↑idx + 1
p_entails_c_arr_j : p ⊨ c_arr[↑j]
acc✝ : ReduceResult (PosFin n)
l : Literal (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) (reducedToUnit l)
x✝ : Assignment
heq✝ : assignment[c_arr[↑idx].fst.val]! = both
h : encounteredBoth = reducedToUnit (i, b)
⊢ p ⊨ (i, b)

case h_4
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
i : PosFin n
b : Bool
p : PosFin n → Bool
hp : p ⊨ assignment
j : Fin c_arr.size
j_lt_idx_add_one : ↑j < ↑idx + 1
p_entails_c_arr_j : p ⊨ c_arr[↑j]
acc✝ : ReduceResult (PosFin n)
l : Literal (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) (reducedToUnit l)
x✝ : Assignment
heq✝ : assignment[c_arr[↑idx].fst.val]! = unassigned
h : reducedToNonunit = reducedToUnit (i, b)
⊢ p ⊨ (i, b)

Proof state:
case h_3
n : Nat
c_arr : Array (Literal (PosFin n))
assignment : Array Assignment
idx : Fin c_arr.size
p : PosFin n → Bool
acc✝ : ReduceResult (PosFin n)
l : Literal (PosFin n)
ih : ReducePostconditionInductionMotive c_arr assignment (↑idx) (reducedToUnit l)
x✝ : Assignment
heq✝ : assignment[c_arr[↑idx].fst.val]! = both
h : encounteredBoth = reducedToEmpty
⊢ (∀ (i : Fin c_arr.size), ↑i < ↑idx + 1 → ¬(p ⊨ c_arr[↑i])) ∨ ¬(p ⊨ assignment)

Tactic:
simp at h

Result:
no goals