-- Mathlib/.lake/packages/lean4/src/lean/Std/Sat/AIG/CachedLemmas.lean
theorem mkGateCached.go_le_size (aig : AIG α) (input : GateInput aig) :
    aig.decls.size ≤ (go aig input).aig.decls.size

Proof state:
case h_2.h_5
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
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
heq✝² : aig.decls[input.lhs.ref.gate] = Decl.const true
heq✝¹ : input.lhs.inv = false
heq✝ : input.rhs.inv = false
x✝ : aig.decls[input.rhs.ref.gate] = Decl.const false → False
⊢ aig.decls.size ≤
    { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
            ref := { gate := input.rhs.ref.gate, hgate := ⋯ } }.aig.decls.size

Tactic:
simp_arith

Result:
no goals

Proof state:
case h_2.h_6
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
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
heq✝² : aig.decls[input.lhs.ref.gate] = Decl.const false
heq✝¹ : input.lhs.inv = true
heq✝ : input.rhs.inv = false
x✝ : aig.decls[input.rhs.ref.gate] = Decl.const false → False
⊢ aig.decls.size ≤
    { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
            ref := { gate := input.rhs.ref.gate, hgate := ⋯ } }.aig.decls.size

Tactic:
simp_arith

Result:
no goals

Proof state:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
⊢ aig.decls.size ≤ (go aig input).aig.decls.size

Tactic:
dsimp only [go]

Result:
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
⊢ aig.decls.size ≤
    (match aig.cache.get? (Decl.gate input.lhs.ref.gate input.rhs.ref.gate input.lhs.inv input.rhs.inv) with
          | some hit =>
            { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
              ref := { gate := hit.idx, hgate := ⋯ } }
          | none =>
            match aig.decls[input.lhs.ref.gate], aig.decls[input.rhs.ref.gate], input.lhs.inv, input.rhs.inv with
            | Decl.const true, x, true, x_1 =>
              { decls := aig.decls, cache := aig.cache, invariant := ⋯ }.mkConstCached false
            | Decl.const false, x, false, x_1 =>
              { decls := aig.decls, cache := aig.cache, invariant := ⋯ }.mkConstCached false
            | x, Decl.const true, x_1, true =>
              { decls := aig.decls, cache := aig.cache, invariant := ⋯ }.mkConstCached false
            | x, Decl.const false, x_1, false =>
              { decls := aig.decls, cache := aig.cache, invariant := ⋯ }.mkConstCached false
            | Decl.const true, x, false, false =>
              { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
                ref := { gate := input.rhs.ref.gate, hgate := ⋯ } }
            | Decl.const false, x, true, false =>
              { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
                ref := { gate := input.rhs.ref.gate, hgate := ⋯ } }
            | x, Decl.const true, false, false =>
              { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
                ref := { gate := input.lhs.ref.gate, hgate := ⋯ } }
            | x, Decl.const false, false, true =>
              { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
                ref := { gate := input.lhs.ref.gate, hgate := ⋯ } }
            | x, x_1, x_2, x_3 =>
              if
                  (input.lhs.ref.gate == input.rhs.ref.gate && input.lhs.inv == false && input.rhs.inv == false) =
                    true then
                { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
                  ref := { gate := input.lhs.ref.gate, hgate := ⋯ } }
              else
                if (input.lhs.ref.gate == input.rhs.ref.gate && input.lhs.inv == !input.rhs.inv) = true then
                  { decls := aig.decls, cache := aig.cache, invariant := ⋯ }.mkConstCached false
                else
                  {
                    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 := ⋯ } }).aig.decls.size

Proof state:
case h_2.h_8
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
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
heq✝² : aig.decls[input.rhs.ref.gate] = Decl.const false
heq✝¹ : input.lhs.inv = false
heq✝ : input.rhs.inv = true
x✝ : aig.decls[input.lhs.ref.gate] = Decl.const false → False
⊢ aig.decls.size ≤
    { aig := { decls := aig.decls, cache := aig.cache, invariant := ⋯ },
            ref := { gate := input.lhs.ref.gate, hgate := ⋯ } }.aig.decls.size

Tactic:
simp_arith

Result:
no goals

Proof state:
case h_2.h_9.isFalse
α : Type
inst✝¹ : Hashable α
inst✝ : DecidableEq α
aig : AIG α
input : aig.GateInput
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
⊢ aig.decls.size ≤
    (if (input.lhs.ref.gate == input.rhs.ref.gate && input.lhs.inv == !input.rhs.inv) = true then
            { decls := aig.decls, cache := aig.cache, invariant := ⋯ }.mkConstCached false
          else
            {
              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 := ⋯ } }).aig.decls.size

Tactic:
split <;> simp_arith [mkConstCached_le_size]

Result:
no goals