-- Mathlib/.lake/packages/lean4/src/lean/Std/Sat/AIG/RefVecOperator/Fold.lean
theorem denote_go_and {aig : AIG α} (acc : AIG.Ref aig) (curr : Nat) (hcurr : curr ≤ len)
    (input : RefVec aig len) :
    ⟦
      (go aig acc curr len input mkAndCached).aig,
      (go aig acc curr len input mkAndCached).ref,
      assign
    ⟧
      =
    (
      ⟦aig, acc, assign⟧
        ∧
      (∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦aig, input.get idx hidx1, assign⟧)
    )

Proof state:
case isTrue.mpr
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
res : Entrypoint α
h✝ : curr < len
hgo :
  go (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig
      (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref (curr + 1) len (input.cast ⋯) mkAndCached =
    res
⊢ (⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true) →
    (⟦assign, { aig := aig, ref := acc }⟧ = true ∧ ⟦assign, { aig := aig, ref := input.get curr h✝ }⟧ = true) ∧
      ∀ (idx : Nat) (hidx1 : idx < len),
        curr + 1 ≤ idx →
          ⟦assign,
              { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
                ref := (input.get idx hidx1).cast ⋯ }⟧ =
            true

Tactic:
simp only [and_imp]

Result:
case isTrue.mpr
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
res : Entrypoint α
h✝ : curr < len
hgo :
  go (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig
      (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref (curr + 1) len (input.cast ⋯) mkAndCached =
    res
⊢ ⟦assign, { aig := aig, ref := acc }⟧ = true →
    (∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true) →
      (⟦assign, { aig := aig, ref := acc }⟧ = true ∧ ⟦assign, { aig := aig, ref := input.get curr h✝ }⟧ = true) ∧
        ∀ (idx : Nat) (hidx1 : idx < len),
          curr + 1 ≤ idx →
            ⟦assign,
                { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
                  ref := (input.get idx hidx1).cast ⋯ }⟧ =
              true

Proof state:
case isTrue.mp.intro.intro
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
res : Entrypoint α
h✝ : curr < len
hgo :
  go (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig
      (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref (curr + 1) len (input.cast ⋯) mkAndCached =
    res
h3 :
  ∀ (idx : Nat) (hidx1 : idx < len),
    curr + 1 ≤ idx →
      ⟦assign,
          { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
            ref := (input.get idx hidx1).cast ⋯ }⟧ =
        true
h1 : ⟦assign, { aig := aig, ref := acc }⟧ = true
h2 : ⟦assign, { aig := aig, ref := input.get curr h✝ }⟧ = true
⊢ ⟦assign, { aig := aig, ref := acc }⟧ = true ∧
    ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true

Tactic:
constructor

Result:
case isTrue.mp.intro.intro.left
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
res : Entrypoint α
h✝ : curr < len
hgo :
  go (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig
      (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref (curr + 1) len (input.cast ⋯) mkAndCached =
    res
h3 :
  ∀ (idx : Nat) (hidx1 : idx < len),
    curr + 1 ≤ idx →
      ⟦assign,
          { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
            ref := (input.get idx hidx1).cast ⋯ }⟧ =
        true
h1 : ⟦assign, { aig := aig, ref := acc }⟧ = true
h2 : ⟦assign, { aig := aig, ref := input.get curr h✝ }⟧ = true
⊢ ⟦assign, { aig := aig, ref := acc }⟧ = true

case isTrue.mp.intro.intro.right
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
res : Entrypoint α
h✝ : curr < len
hgo :
  go (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig
      (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref (curr + 1) len (input.cast ⋯) mkAndCached =
    res
h3 :
  ∀ (idx : Nat) (hidx1 : idx < len),
    curr + 1 ≤ idx →
      ⟦assign,
          { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
            ref := (input.get idx hidx1).cast ⋯ }⟧ =
        true
h1 : ⟦assign, { aig := aig, ref := acc }⟧ = true
h2 : ⟦assign, { aig := aig, ref := input.get curr h✝ }⟧ = true
⊢ ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true

Proof state:
case isTrue
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
res : Entrypoint α
h✝ : curr < len
hgo :
  go (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig
      (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref (curr + 1) len (input.cast ⋯) mkAndCached =
    res
⊢ (⟦assign,
          { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
            ref := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref }⟧ =
        true ∧
      ∀ (idx : Nat) (hidx1 : idx < len),
        curr + 1 ≤ idx →
          ⟦assign,
              { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
                ref := (input.cast ⋯).get idx hidx1 }⟧ =
            true) =
    (⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true)

Tactic:
simp only [denote_projected_entry, denote_mkAndCached, Bool.and_eq_true, get_cast,
  eq_iff_iff]

Result:
case isTrue
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
res : Entrypoint α
h✝ : curr < len
hgo :
  go (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig
      (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).ref (curr + 1) len (input.cast ⋯) mkAndCached =
    res
⊢ ((⟦assign, { aig := aig, ref := acc }⟧ = true ∧ ⟦assign, { aig := aig, ref := input.get curr h✝ }⟧ = true) ∧
      ∀ (idx : Nat) (hidx1 : idx < len),
        curr + 1 ≤ idx →
          ⟦assign,
              { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig,
                ref := (input.get idx hidx1).cast ⋯ }⟧ =
            true) ↔
    ⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true