-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/Bitblast/BVExpr/Circuit/Lemmas/Expr.lean
theorem go_denote_eq (aig : AIG BVBit) (expr : BVExpr w) (assign : Assignment) :
    ∀ (idx : Nat) (hidx : idx < w),
        ⟦(go aig expr).val.aig, (go aig expr).val.vec.get idx hidx, assign.toAIGAssignment⟧
          =
        (expr.eval assign).getLsbD idx

Proof state:
case bin.udiv
w : Nat
assign : Assignment
w✝ : Nat
lhs rhs : BVExpr w✝
lih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment, { aig := (go aig lhs).val.aig, ref := (go aig lhs).val.vec.get idx hidx }⟧ =
      (eval assign lhs).getLsbD idx
rih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment, { aig := (go aig rhs).val.aig, ref := (go aig rhs).val.vec.get idx hidx }⟧ =
      (eval assign rhs).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < w✝
⊢ ⟦assign.toAIGAssignment,
      {
        aig :=
          (blastUdiv (go (go aig lhs).1.aig rhs).1.aig
              { lhs := (go aig lhs).1.vec.cast ⋯, rhs := (go (go aig lhs).1.aig rhs).1.vec }).aig,
        ref :=
          (blastUdiv (go (go aig lhs).1.aig rhs).1.aig
                  { lhs := (go aig lhs).1.vec.cast ⋯, rhs := (go (go aig lhs).1.aig rhs).1.vec }).vec.get
            idx hidx }⟧ =
    (eval assign lhs / eval assign rhs).getLsbD idx

Tactic:
apply denote_blastUdiv

Result:
case bin.udiv.hleft
w : Nat
assign : Assignment
w✝ : Nat
lhs rhs : BVExpr w✝
lih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment, { aig := (go aig lhs).val.aig, ref := (go aig lhs).val.vec.get idx hidx }⟧ =
      (eval assign lhs).getLsbD idx
rih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment, { aig := (go aig rhs).val.aig, ref := (go aig rhs).val.vec.get idx hidx }⟧ =
      (eval assign rhs).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < w✝
⊢ ∀ (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment,
        { aig := (go (go aig lhs).1.aig rhs).1.aig,
          ref := { lhs := (go aig lhs).1.vec.cast ⋯, rhs := (go (go aig lhs).1.aig rhs).1.vec }.lhs.get idx hidx }⟧ =
      (eval assign lhs).getLsbD idx

case bin.udiv.hright
w : Nat
assign : Assignment
w✝ : Nat
lhs rhs : BVExpr w✝
lih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment, { aig := (go aig lhs).val.aig, ref := (go aig lhs).val.vec.get idx hidx }⟧ =
      (eval assign lhs).getLsbD idx
rih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment, { aig := (go aig rhs).val.aig, ref := (go aig rhs).val.vec.get idx hidx }⟧ =
      (eval assign rhs).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < w✝
⊢ ∀ (idx : Nat) (hidx : idx < w✝),
    ⟦assign.toAIGAssignment,
        { aig := (go (go aig lhs).1.aig rhs).1.aig,
          ref := { lhs := (go aig lhs).1.vec.cast ⋯, rhs := (go (go aig lhs).1.aig rhs).1.vec }.rhs.get idx hidx }⟧ =
      (eval assign rhs).getLsbD idx

Proof state:
case arithShiftRight
w : Nat
assign : Assignment
m✝ n✝ : Nat
lhs : BVExpr m✝
rhs : BVExpr n✝
lih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < m✝),
    ⟦assign.toAIGAssignment, { aig := (go aig lhs).val.aig, ref := (go aig lhs).val.vec.get idx hidx }⟧ =
      (eval assign lhs).getLsbD idx
rih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < n✝),
    ⟦assign.toAIGAssignment, { aig := (go aig rhs).val.aig, ref := (go aig rhs).val.vec.get idx hidx }⟧ =
      (eval assign rhs).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < m✝
⊢ ⟦assign.toAIGAssignment,
      {
        aig :=
          (blastArithShiftRight (go (go aig lhs).1.aig rhs).1.aig
              { n := n✝, target := (go aig lhs).1.vec.cast ⋯, distance := (go (go aig lhs).1.aig rhs).1.vec }).aig,
        ref :=
          (blastArithShiftRight (go (go aig lhs).1.aig rhs).1.aig
                  { n := n✝, target := (go aig lhs).1.vec.cast ⋯,
                    distance := (go (go aig lhs).1.aig rhs).1.vec }).vec.get
            idx hidx }⟧ =
    ((eval assign lhs).sshiftRight' (eval assign rhs)).getLsbD idx

Tactic:
apply denote_blastArithShiftRight

Result:
case arithShiftRight.hleft
w : Nat
assign : Assignment
m✝ n✝ : Nat
lhs : BVExpr m✝
rhs : BVExpr n✝
lih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < m✝),
    ⟦assign.toAIGAssignment, { aig := (go aig lhs).val.aig, ref := (go aig lhs).val.vec.get idx hidx }⟧ =
      (eval assign lhs).getLsbD idx
rih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < n✝),
    ⟦assign.toAIGAssignment, { aig := (go aig rhs).val.aig, ref := (go aig rhs).val.vec.get idx hidx }⟧ =
      (eval assign rhs).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < m✝
⊢ ∀ (idx : Nat) (hidx : idx < m✝),
    ⟦assign.toAIGAssignment,
        { aig := (go (go aig lhs).1.aig rhs).1.aig,
          ref :=
            { n := n✝, target := (go aig lhs).1.vec.cast ⋯, distance := (go (go aig lhs).1.aig rhs).1.vec }.target.get
              idx hidx }⟧ =
      (eval assign lhs).getLsbD idx

case arithShiftRight.hright
w : Nat
assign : Assignment
m✝ n✝ : Nat
lhs : BVExpr m✝
rhs : BVExpr n✝
lih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < m✝),
    ⟦assign.toAIGAssignment, { aig := (go aig lhs).val.aig, ref := (go aig lhs).val.vec.get idx hidx }⟧ =
      (eval assign lhs).getLsbD idx
rih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < n✝),
    ⟦assign.toAIGAssignment, { aig := (go aig rhs).val.aig, ref := (go aig rhs).val.vec.get idx hidx }⟧ =
      (eval assign rhs).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < m✝
⊢ ∀ (idx : Nat)
    (hidx : idx < { n := n✝, target := (go aig lhs).1.vec.cast ⋯, distance := (go (go aig lhs).1.aig rhs).1.vec }.n),
    ⟦assign.toAIGAssignment,
        { aig := (go (go aig lhs).1.aig rhs).1.aig,
          ref :=
            { n := n✝, target := (go aig lhs).1.vec.cast ⋯, distance := (go (go aig lhs).1.aig rhs).1.vec }.distance.get
              idx hidx }⟧ =
      (eval assign rhs).getLsbD idx