-- Mathlib/.lake/packages/lean4/src/lean/Std/Sat/AIG/CachedLemmas.lean
theorem mkGateCached.go_decl_eq (aig : AIG α) (input : GateInput aig) :
    ∀ (idx : Nat) (h1) (h2), (go aig input).aig.decls[idx]'h1 = aig.decls[idx]'h2

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
res : Entrypoint α
hres : go aig input = res
⊢ ∀ (idx : Nat) (h1 : idx < res.aig.decls.size) (h2 : idx < aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Tactic:
unfold go at hres

Result:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
res : Entrypoint α
hres :
  (match aig, input with
    | { decls := decls, cache := cache, invariant := inv }, input =>
      let lhs := input.lhs.ref.gate;
      let rhs := input.rhs.ref.gate;
      let linv := input.lhs.inv;
      let rinv := input.rhs.inv;
      let_fun this := ⋯;
      let_fun this_1 := ⋯;
      let decl := Decl.gate lhs rhs linv rinv;
      match cache.get? decl with
      | some hit =>
        { aig := { decls := decls, cache := cache, invariant := ⋯ }, ref := { gate := hit.idx, hgate := ⋯ } }
      | none =>
        match decls[lhs], decls[rhs], linv, rinv with
        | Decl.const true, x, true, x_1 => { decls := decls, cache := cache, invariant := ⋯ }.mkConstCached false
        | Decl.const false, x, false, x_1 => { decls := decls, cache := cache, invariant := ⋯ }.mkConstCached false
        | x, Decl.const true, x_1, true => { decls := decls, cache := cache, invariant := ⋯ }.mkConstCached false
        | x, Decl.const false, x_1, false => { decls := decls, cache := cache, invariant := ⋯ }.mkConstCached false
        | Decl.const true, x, false, false =>
          { aig := { decls := decls, cache := cache, invariant := ⋯ }, ref := { gate := rhs, hgate := this_1 } }
        | Decl.const false, x, true, false =>
          { aig := { decls := decls, cache := cache, invariant := ⋯ }, ref := { gate := rhs, hgate := this_1 } }
        | x, Decl.const true, false, false =>
          { aig := { decls := decls, cache := cache, invariant := ⋯ }, ref := { gate := lhs, hgate := this } }
        | x, Decl.const false, false, true =>
          { aig := { decls := decls, cache := cache, invariant := ⋯ }, ref := { gate := lhs, hgate := this } }
        | x, x_1, x_2, x_3 =>
          if (lhs == rhs && linv == false && rinv == false) = true then
            { aig := { decls := decls, cache := cache, invariant := ⋯ }, ref := { gate := lhs, hgate := this } }
          else
            if (lhs == rhs && linv == !rinv) = true then
              { decls := decls, cache := cache, invariant := ⋯ }.mkConstCached false
            else
              let g := decls.size;
              let cache_1 := Cache.insert decls cache decl;
              let decls_1 := decls.push decl;
              let_fun inv_1 := ⋯;
              { aig := { decls := decls_1, cache := cache_1, invariant := inv_1 }, ref := { gate := g, hgate := ⋯ } }) =
    res
⊢ ∀ (idx : Nat) (h1 : idx < res.aig.decls.size) (h2 : idx < aig.decls.size), res.aig.decls[idx] = aig.decls[idx]

Proof state:
case h_1
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
res : Entrypoint α
x✝ : Option (CacheHit aig.decls (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv))
hit✝ : CacheHit aig.decls (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv)
heq✝ : aig.cache.get? (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv) = some hit✝
hres :
  { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ }, ref := { gate := hit✝.idx, hgate := ⋯ } } = res
⊢ ∀ (idx : Nat)
    (h1 :
      idx <
        { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
                ref := { gate := hit✝.idx, hgate := ⋯ } }.aig.decls.size)
    (h2 : idx < aig.decls.size),
    { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
              ref := { gate := hit✝.idx, hgate := ⋯ } }.aig.decls[idx] =
      aig.decls[idx]

Tactic:
intros

Result:
case h_1
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
res : Entrypoint α
x✝ : Option (CacheHit aig.decls (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv))
hit✝ : CacheHit aig.decls (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv)
heq✝ : aig.cache.get? (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv) = some hit✝
hres :
  { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ }, ref := { gate := hit✝.idx, hgate := ⋯ } } = res
idx✝ : Nat
h1✝ :
  idx✝ <
    { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
            ref := { gate := hit✝.idx, hgate := ⋯ } }.aig.decls.size
h2✝ : idx✝ < aig.decls.size
⊢ { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
            ref := { gate := hit✝.idx, hgate := ⋯ } }.aig.decls[idx✝] =
    aig.decls[idx✝]

Proof state:
case h_2.h_9.isFalse.isFalse
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
res : Entrypoint α
x✝¹⁰ : Option (CacheHit aig.decls (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv))
heq✝ : aig.cache.get? (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv) = none
x✝⁹ x✝⁸ : Decl α
linv✝ rinv✝ : Bool
x✝⁷ : aig.decls[input.lhs.ref.gate] = Decl.const true → input.lhs.inv = true → False
x✝⁶ : aig.decls[input.lhs.ref.gate] = Decl.const false → input.lhs.inv = false → False
x✝⁵ : aig.decls[input.rhs.ref.gate] = Decl.const true → input.rhs.inv = true → False
x✝⁴ : aig.decls[input.rhs.ref.gate] = Decl.const false → input.rhs.inv = false → False
x✝³ : aig.decls[input.lhs.ref.gate] = Decl.const true → input.lhs.inv = false → input.rhs.inv = false → False
x✝² : aig.decls[input.lhs.ref.gate] = Decl.const false → input.lhs.inv = true → input.rhs.inv = false → False
x✝¹ : aig.decls[input.rhs.ref.gate] = Decl.const true → input.lhs.inv = false → input.rhs.inv = false → False
x✝ : aig.decls[input.rhs.ref.gate] = Decl.const false → input.lhs.inv = false → input.rhs.inv = true → False
h✝¹ : ¬(input.lhs.ref.gate == input.rhs.ref.gate && input.lhs.inv == false && input.rhs.inv == false) = true
h✝ : ¬(input.lhs.ref.gate == input.rhs.ref.gate && input.lhs.inv == !input.rhs.inv) = true
hres :
  {
      aig :=
        { decls := aig.decls.push (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv),
          cache :=
            Cache.insert aig.decls aig.cache
              (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv),
          invariant := ⋯ },
      ref := { gate := aig.decls.size, hgate := ⋯ } } =
    res
idx : Nat
h1 : idx < (aig.decls.push (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv)).size
h2 : idx < aig.decls.size
⊢ (if h : idx < aig.decls.size then aig.decls[idx]
    else Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv) =
    aig.decls[idx]

Tactic:
simp [h2]

Result:
no goals