-- 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.mul
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 := (go aig (lhs.bin BVBinOp.mul rhs)).val.aig,
        ref := (go aig (lhs.bin BVBinOp.mul rhs)).val.vec.get idx hidx }⟧ =
    (eval assign (lhs.bin BVBinOp.mul rhs)).getLsbD idx

Tactic:
simp only [go, eval_bin, BVBinOp.eval_mul]

Result:
case bin.mul
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 :=
          (blastMul (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 :=
          (blastMul (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

Proof state:
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✝

Tactic:
rw [← rih]

Result:
no goals

Proof state:
case signExtend.inr
w : Nat
assign : Assignment
originalWidth v : Nat
inner : BVExpr originalWidth
ih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < originalWidth),
    ⟦assign.toAIGAssignment, { aig := (go aig inner).val.aig, ref := (go aig inner).val.vec.get idx hidx }⟧ =
      (eval assign inner).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < v
res : RefVecEntry BVBit v
hgo : blastSignExtend (go aig inner).1.aig { w := originalWidth, vec := (go aig inner).1.vec } = res
this : 0 ≤ originalWidth
hlt : 0 < originalWidth
⊢ ⟦assign.toAIGAssignment, { aig := res.aig, ref := res.vec.get idx hidx }⟧ =
    (eval assign (signExtend v inner)).getLsbD idx

Tactic:
rw [← hgo]

Result:
case signExtend.inr
w : Nat
assign : Assignment
originalWidth v : Nat
inner : BVExpr originalWidth
ih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < originalWidth),
    ⟦assign.toAIGAssignment, { aig := (go aig inner).val.aig, ref := (go aig inner).val.vec.get idx hidx }⟧ =
      (eval assign inner).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < v
res : RefVecEntry BVBit v
hgo : blastSignExtend (go aig inner).1.aig { w := originalWidth, vec := (go aig inner).1.vec } = res
this : 0 ≤ originalWidth
hlt : 0 < originalWidth
⊢ ⟦assign.toAIGAssignment,
      { aig := (blastSignExtend (go aig inner).1.aig { w := originalWidth, vec := (go aig inner).1.vec }).aig,
        ref :=
          (blastSignExtend (go aig inner).1.aig { w := originalWidth, vec := (go aig inner).1.vec }).vec.get idx
            hidx }⟧ =
    (eval assign (signExtend v inner)).getLsbD idx

Proof state:
case bin.mul.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✝

Tactic:
rw [← rih]

Result:
no goals

Proof state:
case bin.umod.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 aig lhs).1.aig,
        ref := { gate := (((go aig lhs).1.vec.cast ⋯).get idx✝ hidx✝).gate, hgate := ?bin.umod.hleft.hstart } }⟧ =
    ⟦assign.toAIGAssignment, { aig := (go aig lhs).val.aig, ref := (go aig lhs).val.vec.get idx✝ ?bin.umod.hleft.hidx }⟧

Tactic:
simp

Result:
no goals

Proof state:
case extract
w✝ : Nat
assign : Assignment
w start len : Nat
inner : BVExpr w
ih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w),
    ⟦assign.toAIGAssignment, { aig := (go aig inner).val.aig, ref := (go aig inner).val.vec.get idx hidx }⟧ =
      (eval assign inner).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < len
⊢ (if h : start + idx < w then
      ⟦assign.toAIGAssignment, { aig := (go aig inner).1.aig, ref := (go aig inner).1.vec.get (start + idx) ⋯ }⟧
    else false) =
    (eval assign inner).getLsbD (start + idx)

Tactic:
split

Result:
case extract.isTrue
w✝ : Nat
assign : Assignment
w start len : Nat
inner : BVExpr w
ih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w),
    ⟦assign.toAIGAssignment, { aig := (go aig inner).val.aig, ref := (go aig inner).val.vec.get idx hidx }⟧ =
      (eval assign inner).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < len
h✝ : start + idx < w
⊢ ⟦assign.toAIGAssignment, { aig := (go aig inner).1.aig, ref := (go aig inner).1.vec.get (start + idx) ⋯ }⟧ =
    (eval assign inner).getLsbD (start + idx)

case extract.isFalse
w✝ : Nat
assign : Assignment
w start len : Nat
inner : BVExpr w
ih :
  ∀ (aig : AIG BVBit) (idx : Nat) (hidx : idx < w),
    ⟦assign.toAIGAssignment, { aig := (go aig inner).val.aig, ref := (go aig inner).val.vec.get idx hidx }⟧ =
      (eval assign inner).getLsbD idx
aig : AIG BVBit
idx : Nat
hidx : idx < len
h✝ : ¬start + idx < w
⊢ false = (eval assign inner).getLsbD (start + idx)