-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/Bitblast/BVExpr/Circuit/Impl/Operations/ShiftRight.lean
theorem blastArithShiftRight.go_decl_eq (aig : AIG α) (distance : AIG.RefVec aig n) (curr : Nat)
    (acc : AIG.RefVec aig w) :
    ∀ (idx : Nat) (h1) (h2),
        (go aig distance curr acc).aig.decls[idx]'h2 = aig.decls[idx]'h1

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < (go aig distance curr acc).aig.decls.size),
    (go aig distance curr acc).aig.decls[idx] = aig.decls[idx]

Tactic:
generalize hgo : go aig distance curr acc = res

Result:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
hgo : go aig distance curr acc = res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < res.aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Proof state:
case isTrue.h2
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
h✝ : curr < n - 1
hgo :
  go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
      (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec =
    res
idx✝ : Nat
h1✝ : idx✝ < aig.decls.size
h2✝ :
  idx✝ <
    (go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
            (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec).aig.decls.size
⊢ idx✝ < (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig.decls.size

Tactic:
apply AIG.LawfulVecOperator.lt_size_of_lt_aig_size (f := blastArithShiftRight.twoPowShift)

Result:
case isTrue.h2.h
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
h✝ : curr < n - 1
hgo :
  go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
      (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec =
    res
idx✝ : Nat
h1✝ : idx✝ < aig.decls.size
h2✝ :
  idx✝ <
    (go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
            (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec).aig.decls.size
⊢ idx✝ < aig.decls.size

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
hgo :
  (if curr < n - 1 then
      go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
        (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec
    else { aig := aig, vec := acc }) =
    res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < res.aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Tactic:
split at hgo

Result:
case isTrue
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
h✝ : curr < n - 1
hgo :
  go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
      (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec =
    res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < res.aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

case isFalse
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
h✝ : ¬curr < n - 1
hgo : { aig := aig, vec := acc } = res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < res.aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
hgo :
  (if curr < n - 1 then
      let res := twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 };
      let aig_1 := res.aig;
      let acc_1 := res.vec;
      let_fun this := ⋯;
      let distance := distance.cast this;
      go aig_1 distance (curr + 1) acc_1
    else { aig := aig, vec := acc }) =
    res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < res.aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Tactic:
dsimp only at hgo

Result:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
hgo :
  (if curr < n - 1 then
      go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
        (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec
    else { aig := aig, vec := acc }) =
    res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < res.aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Proof state:
case isTrue
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
h✝ : curr < n - 1
hgo :
  go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
      (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec =
    res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size) (h2 : idx < res.aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Tactic:
rw [← hgo]

Result:
case isTrue
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
n w : Nat
aig : AIG α
distance : aig.RefVec n
curr : Nat
acc : aig.RefVec w
res : AIG.RefVecEntry α w
h✝ : curr < n - 1
hgo :
  go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
      (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec =
    res
⊢ ∀ (idx : Nat) (h1 : idx < aig.decls.size)
    (h2 :
      idx <
        (go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
                (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec).aig.decls.size),
    (go (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).aig (distance.cast ⋯) (curr + 1)
              (twoPowShift aig { n := n, lhs := acc, rhs := distance, pow := curr + 1 }).vec).aig.decls[idx] =
      aig.decls[idx]