-- 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:
α : 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
hacc : ⟦assign, { aig := aig, ref := acc }⟧ = true
hrest : ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true
idx : Nat
hidx1 : idx < len
hidx2 : curr + 1 ≤ idx
⊢ curr ≤ idx

Tactic:
omega

Result:
no goals

Proof state:
α : 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 α
hgo :
  (if hidx : curr < len then
      let res := aig.mkAndCached { lhs := acc, rhs := input.get curr hidx };
      let aig_1 := res.aig;
      let newAcc := res.ref;
      let input := input.cast ⋯;
      go aig_1 newAcc (curr + 1) len input mkAndCached
    else { aig := aig, ref := acc }) =
    res
⊢ (⟦assign, { aig := res.aig, ref := res.ref }⟧ = true) =
    (⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true)

Tactic:
split at hgo

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 :
  (let res := aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ };
    let aig_1 := res.aig;
    let newAcc := res.ref;
    let input := input.cast ⋯;
    go aig_1 newAcc (curr + 1) len input mkAndCached) =
    res
⊢ (⟦assign, { aig := res.aig, ref := res.ref }⟧ = true) =
    (⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true)

case isFalse
α : 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 : { aig := aig, ref := acc } = res
⊢ (⟦assign, { aig := res.aig, ref := res.ref }⟧ = true) =
    (⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true)

Proof state:
case isTrue.mpr.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
hacc : ⟦assign, { aig := aig, ref := acc }⟧ = true
idx : Nat
hidx1 : idx < len
hidx2 : curr + 1 ≤ idx
hrest : ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true
⊢ ⟦assign,
      { aig := (aig.mkAndCached { lhs := acc, rhs := input.get curr h✝ }).aig, ref := (input.get idx hidx1).cast ⋯ }⟧ =
    ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧

Tactic:
rw [AIG.LawfulOperator.denote_mem_prefix (f := AIG.mkAndCached)]

Result:
case isTrue.mpr.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
hacc : ⟦assign, { aig := aig, ref := acc }⟧ = true
idx : Nat
hidx1 : idx < len
hidx2 : curr + 1 ≤ idx
hrest : ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true
⊢ ⟦assign, { aig := aig, ref := { gate := ((input.get idx hidx1).cast ⋯).gate, hgate := ?isTrue.mpr.right } }⟧ =
    ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧

case isTrue.mpr.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
hacc : ⟦assign, { aig := aig, ref := acc }⟧ = true
idx : Nat
hidx1 : idx < len
hidx2 : curr + 1 ≤ idx
hrest : ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true
⊢ ((input.get idx hidx1).cast ⋯).gate < aig.decls.size

Proof state:
case isFalse
α : 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 : { aig := aig, ref := acc } = res
⊢ ⟦assign, { aig := aig, ref := acc }⟧ = true →
    ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true

Tactic:
omega

Result:
no goals

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
len : Nat
assign : α → Bool
aig : AIG α
acc : aig.Ref
curr : Nat
hcurr : curr ≤ len
input : aig.RefVec len
⊢ (⟦assign,
        { aig := (go aig acc curr len input mkAndCached).aig, ref := (go aig acc curr len input mkAndCached).ref }⟧ =
      true) =
    (⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true)

Tactic:
generalize hgo : go aig acc curr len input mkAndCached = res

Result:
α : 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 α
hgo : go aig acc curr len input mkAndCached = res
⊢ (⟦assign, { aig := res.aig, ref := res.ref }⟧ = true) =
    (⟦assign, { aig := aig, ref := acc }⟧ = true ∧
      ∀ (idx : Nat) (hidx1 : idx < len), curr ≤ idx → ⟦assign, { aig := aig, ref := input.get idx hidx1 }⟧ = true)