-- Mathlib/.lake/packages/lean4/src/lean/Std/Tactic/BVDecide/Bitblast/BVExpr/Circuit/Lemmas/Operations/ShiftRight.lean
theorem denote_blastArithShiftRightConst (aig : AIG α) (target : ShiftTarget aig w)
    (assign : α → Bool) :
    ∀ (idx : Nat) (hidx : idx < w),
        ⟦
          (blastArithShiftRightConst aig target).aig,
          (blastArithShiftRightConst aig target).vec.get idx hidx,
          assign
        ⟧
          =
        if hidx : (target.distance + idx) < w then
          ⟦aig, target.vec.get (target.distance + idx) (by omega), assign⟧
        else
          ⟦aig, target.vec.get (w - 1) (by omega), assign⟧

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx : Nat
hidx✝ : idx < w
hidx : ¬target.distance + idx < w
⊢ w - 1 < w

Tactic:
omega

Result:
no goals

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
⊢ ∀ (idx : Nat) (hidx : idx < w),
    ⟦assign,
        { aig := (blastArithShiftRightConst aig target).aig,
          ref := (blastArithShiftRightConst aig target).vec.get idx hidx }⟧ =
      if hidx : target.distance + idx < w then ⟦assign, { aig := aig, ref := target.vec.get (target.distance + idx) ⋯ }⟧
      else ⟦assign, { aig := aig, ref := target.vec.get (w - 1) ⋯ }⟧

Tactic:
intros

Result:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx✝ : Nat
hidx✝ : idx✝ < w
⊢ ⟦assign,
      { aig := (blastArithShiftRightConst aig target).aig,
        ref := (blastArithShiftRightConst aig target).vec.get idx✝ hidx✝ }⟧ =
    if hidx : target.distance + idx✝ < w then ⟦assign, { aig := aig, ref := target.vec.get (target.distance + idx✝) ⋯ }⟧
    else ⟦assign, { aig := aig, ref := target.vec.get (w - 1) ⋯ }⟧

Proof state:
case a
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx✝ : Nat
hidx✝ : idx✝ < w
⊢ 0 ≤ idx✝

Tactic:
omega

Result:
no goals

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx✝ : Nat
hidx✝ : idx✝ < w
⊢ ⟦assign,
      {
        aig :=
          (match target with
            | { vec := input, distance := distance } =>
              { aig := aig, vec := blastArithShiftRightConst.go input distance 0 ⋯ RefVec.empty }).aig,
        ref :=
          (match target with
                | { vec := input, distance := distance } =>
                  { aig := aig, vec := blastArithShiftRightConst.go input distance 0 ⋯ RefVec.empty }).vec.get
            idx✝ hidx✝ }⟧ =
    if hidx : target.distance + idx✝ < w then ⟦assign, { aig := aig, ref := target.vec.get (target.distance + idx✝) ⋯ }⟧
    else ⟦assign, { aig := aig, ref := target.vec.get (w - 1) ⋯ }⟧

Tactic:
rw [blastArithShiftRightConst.go_denote_eq]

Result:
case a
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx✝ : Nat
hidx✝ : idx✝ < w
⊢ 0 ≤ idx✝

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx : Nat
hidx✝ : idx < w
hidx : target.distance + idx < w
⊢ target.distance + idx < w

Tactic:
omega

Result:
no goals

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx✝ : Nat
hidx✝ : idx✝ < w
⊢ ⟦assign,
      { aig := (blastArithShiftRightConst aig target).aig,
        ref := (blastArithShiftRightConst aig target).vec.get idx✝ hidx✝ }⟧ =
    if hidx : target.distance + idx✝ < w then ⟦assign, { aig := aig, ref := target.vec.get (target.distance + idx✝) ⋯ }⟧
    else ⟦assign, { aig := aig, ref := target.vec.get (w - 1) ⋯ }⟧

Tactic:
unfold blastArithShiftRightConst

Result:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
w : Nat
aig : AIG α
target : aig.ShiftTarget w
assign : α → Bool
idx✝ : Nat
hidx✝ : idx✝ < w
⊢ ⟦assign,
      {
        aig :=
          (match target with
            | { vec := input, distance := distance } =>
              { aig := aig, vec := blastArithShiftRightConst.go input distance 0 ⋯ RefVec.empty }).aig,
        ref :=
          (match target with
                | { vec := input, distance := distance } =>
                  { aig := aig, vec := blastArithShiftRightConst.go input distance 0 ⋯ RefVec.empty }).vec.get
            idx✝ hidx✝ }⟧ =
    if hidx : target.distance + idx✝ < w then ⟦assign, { aig := aig, ref := target.vec.get (target.distance + idx✝) ⋯ }⟧
    else ⟦assign, { aig := aig, ref := target.vec.get (w - 1) ⋯ }⟧