l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem card_Ioc : (Ioc a b).card = b - a := by
  rw [← Nat.card_Ioc]
  -- porting note: I had to change this to `erw` *and* provide the proof, yuck.
  -- https://github.com/leanprover-community/mathlib4/issues/5164
  

Proof state:
a b : ℕ+
⊢ card (Ioc a b) = card (Ioc ↑a ↑b)

Next tactic:
erw [← Finset.map_subtype_embedding_Ioc _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
@[simp]
theorem card_Ioc : (Ioc a b).card = b - a := by
  rw [← Nat.card_Ioc]
  -- porting note: I had to change this to `erw` *and* provide the proof, yuck.
  -- https://github.com/leanprover-community/mathlib4/issues/5164
  erw [← Finset.map_subtype_embedding_Ioc _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
  

Proof state:
a b : ℕ+
⊢ card (Ioc a b) = card (map (Embedding.subtype fun n => 0 < n) (Ioc a b))

Next tactic:
rw [card_map]
@[simp]
theorem card_Ioo : (Ioo a b).card = b - a - 1 := by
  

Proof state:
a b : ℕ+
⊢ card (Ioo a b) = ↑b - ↑a - 1

Next tactic:
rw [← Nat.card_Ioo]
@[simp]
theorem card_Ioo : (Ioo a b).card = b - a - 1 := by
  rw [← Nat.card_Ioo]
  -- porting note: I had to change this to `erw` *and* provide the proof, yuck.
  -- https://github.com/leanprover-community/mathlib4/issues/5164
  

Proof state:
a b : ℕ+
⊢ card (Ioo a b) = card (Ioo ↑a ↑b)

Next tactic:
erw [← Finset.map_subtype_embedding_Ioo _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
@[simp]
theorem card_Ioo : (Ioo a b).card = b - a - 1 := by
  rw [← Nat.card_Ioo]
  -- porting note: I had to change this to `erw` *and* provide the proof, yuck.
  -- https://github.com/leanprover-community/mathlib4/issues/5164
  erw [← Finset.map_subtype_embedding_Ioo _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
  

Proof state:
a b : ℕ+
⊢ card (Ioo a b) = card (map (Embedding.subtype fun n => 0 < n) (Ioo a b))

Next tactic:
rw [card_map]
@[simp]
theorem card_uIcc : (uIcc a b).card = (b - a : ℤ).natAbs + 1 := by
  

Proof state:
a b : ℕ+
⊢ card (uIcc a b) = Int.natAbs (↑↑b - ↑↑a) + 1

Next tactic:
rw [← Nat.card_uIcc, ← map_subtype_embedding_uIcc, card_map]
theorem card_fintype_Icc : Fintype.card (Set.Icc a b) = b + 1 - a := by
  

Proof state:
a b : ℕ+
⊢ Fintype.card ↑(Set.Icc a b) = ↑b + 1 - ↑a

Next tactic:
rw [← card_Icc, Fintype.card_ofFinset]
theorem card_fintype_Ico : Fintype.card (Set.Ico a b) = b - a := by
  

Proof state:
a b : ℕ+
⊢ Fintype.card ↑(Set.Ico a b) = ↑b - ↑a

Next tactic:
rw [← card_Ico, Fintype.card_ofFinset]
theorem card_fintype_Ioc : Fintype.card (Set.Ioc a b) = b - a := by
  

Proof state:
a b : ℕ+
⊢ Fintype.card ↑(Set.Ioc a b) = ↑b - ↑a

Next tactic:
rw [← card_Ioc, Fintype.card_ofFinset]
theorem card_fintype_Ioo : Fintype.card (Set.Ioo a b) = b - a - 1 := by
  

Proof state:
a b : ℕ+
⊢ Fintype.card ↑(Set.Ioo a b) = ↑b - ↑a - 1

Next tactic:
rw [← card_Ioo, Fintype.card_ofFinset]
theorem card_fintype_uIcc : Fintype.card (Set.uIcc a b) = (b - a : ℤ).natAbs + 1 := by
  

Proof state:
a b : ℕ+
⊢ Fintype.card ↑(Set.uIcc a b) = Int.natAbs (↑↑b - ↑↑a) + 1

Next tactic:
rw [← card_uIcc, Fintype.card_ofFinset]
theorem IsNatPowT.bit0 : IsNatPowT (Nat.pow a b = c) a (nat_lit 2 * b) (Nat.mul c c) :=
  ⟨fun h1 => by 

Proof state:
a b : ℕ
c : ℕ
h1 : Nat.pow a b = c
⊢ Nat.pow a (2 * b) = Nat.mul c c

Next tactic:
simp [two_mul, pow_add, ← h1]
theorem IsNatPowT.bit1 :
    IsNatPowT (Nat.pow a b = c) a (nat_lit 2 * b + nat_lit 1) (Nat.mul c (Nat.mul c a)) :=
  ⟨fun h1 => by 

Proof state:
a b : ℕ
c : ℕ
h1 : Nat.pow a b = c
⊢ Nat.pow a (2 * b + 1) = Nat.mul c (Nat.mul c a)

Next tactic:
simp [two_mul, pow_add, mul_assoc, ← h1]
/--
Proves `Nat.pow a b = c` where `a` and `b` are raw nat literals. This could be done by just
`rfl` but the kernel does not have a special case implementation for `Nat.pow` so this would
proceed by unary recursion on `b`, which is too slow and also leads to deep recursion.

We instead do the proof by binary recursion, but this can still lead to deep recursion,
so we use an additional trick to do binary subdivision on `log2 b`. As a result this produces
a proof of depth `log (log b)` which will essentially never overflow before the numbers involved
themselves exceed memory limits.
-/
partial def evalNatPow (a b : Q(ℕ)) : (c : Q(ℕ)) × Q(Nat.pow $a $b = $c) :=
  if b.natLit! = 0 then
    haveI : $b =Q 0 := ⟨⟩
    ⟨q(nat_lit 1), q(natPow_zero)⟩
  else if a.natLit! = 0 then
    haveI : $a =Q 0 := ⟨⟩
    have b' : Q(ℕ) := mkRawNatLit (b.natLit! - 1)
    haveI : $b =Q Nat.succ $b' := ⟨⟩
    ⟨q(nat_lit 0), q(zero_natPow)⟩
  else if a.natLit! = 1 then
    haveI : $a =Q 1 := ⟨⟩
    ⟨q(nat_lit 1), q(one_natPow)⟩
  else if b.natLit! = 1 then
    haveI : $b =Q 1 := ⟨⟩
    ⟨a, q(natPow_one)⟩
  else
    let ⟨c, p⟩ := go b.natLit!.log2 a (mkRawNatLit 1) a b _ .rfl
    ⟨c, q(($p).run)⟩
where
  /-- Invariants: `a ^ b₀ = c₀`, `depth > 0`, `b >>> depth = b₀`, `p := Nat.pow $a $b₀ = $c₀` -/
  go (depth : Nat) (a b₀ c₀ b : Q(ℕ)) (p : Q(Prop)) (hp : $p =Q (Nat.pow $a $b₀ = $c₀)) :
      (c : Q(ℕ)) × Q(IsNatPowT $p $a $b $c) :=
    let b' := b.natLit!
    if depth ≤ 1 then
      let a' := a.natLit!
      let c₀' := c₀.natLit!
      if b' &&& 1 == 0 then
        have c : Q(ℕ) := mkRawNatLit (c₀' * c₀')
        haveI : $c =Q Nat.mul $c₀ $c₀ := ⟨⟩
        haveI : $b =Q 2 * $b₀ := ⟨⟩
        ⟨c, q(IsNatPowT.bit0)⟩
      else
        have c : Q(ℕ) := mkRawNatLit (c₀' * (c₀' * a'))
        haveI : $c =Q Nat.mul $c₀ (Nat.mul $c₀ $a) := ⟨⟩
        haveI : $b =Q 2 * $b₀ + 1 := ⟨⟩
        ⟨c, q(IsNatPowT.bit1)⟩
    else
      let d := depth >>> 1
      have hi : Q(ℕ) := mkRawNatLit (b' >>> d)
      let ⟨c1, p1⟩ := go (depth - d) a b₀ c₀ hi p (by 

Proof state:
a✝ b✝ : Q(ℕ)
depth : ℕ
a b₀ c₀ b : Q(ℕ)
p : Q(Prop)
hp : «$p» =Q (Nat.pow «$a» «$b₀» = «$c₀»)
b' : ℕ := Expr.natLit! b
d : ℕ := depth >>> 1
hi : Q(ℕ)
⊢ «$p» =Q (Nat.pow «$a» «$b₀» = «$c₀»)

Next tactic:
exact hp
theorem intPow_ofNat (h1 : Nat.pow a b = c) :
    Int.pow (Int.ofNat a) b = Int.ofNat c := by 

Proof state:
a b : ℕ
c : ℕ
h1 : Nat.pow a b = c
⊢ Int.pow (Int.ofNat a) b = Int.ofNat c

Next tactic:
simp [← h1]
theorem intPow_negOfNat_bit0 (h1 : Nat.pow a b' = c')
    (hb : nat_lit 2 * b' = b) (hc : c' * c' = c) :
    Int.pow (Int.negOfNat a) b = Int.ofNat c := by
  

Proof state:
a b' : ℕ
c' b c : ℕ
h1 : Nat.pow a b' = c'
hb : 2 * b' = b
hc : c' * c' = c
⊢ Int.pow (Int.negOfNat a) b = Int.ofNat c

Next tactic:
rw [← hb, Int.negOfNat_eq, pow_eq, pow_mul, neg_pow_two, ← pow_mul, two_mul, pow_add, ← hc, ← h1]
theorem intPow_negOfNat_bit0 (h1 : Nat.pow a b' = c')
    (hb : nat_lit 2 * b' = b) (hc : c' * c' = c) :
    Int.pow (Int.negOfNat a) b = Int.ofNat c := by
  rw [← hb, Int.negOfNat_eq, pow_eq, pow_mul, neg_pow_two, ← pow_mul, two_mul, pow_add, ← hc, ← h1]
  

Proof state:
a b' : ℕ
c' b c : ℕ
h1 : Nat.pow a b' = c'
hb : 2 * b' = b
hc : c' * c' = c
⊢ Int.ofNat a ^ b' * Int.ofNat a ^ b' = Int.ofNat (Nat.pow a b' * Nat.pow a b')

Next tactic:
simp
theorem intPow_negOfNat_bit1 (h1 : Nat.pow a b' = c')
    (hb : nat_lit 2 * b' + nat_lit 1 = b) (hc : c' * (c' * a) = c) :
    Int.pow (Int.negOfNat a) b = Int.negOfNat c := by
  

Proof state:
a b' : ℕ
c' b c : ℕ
h1 : Nat.pow a b' = c'
hb : 2 * b' + 1 = b
hc : c' * (c' * a) = c
⊢ Int.pow (Int.negOfNat a) b = Int.negOfNat c

Next tactic:
rw [← hb, Int.negOfNat_eq, Int.negOfNat_eq, pow_eq, pow_succ, pow_mul, neg_pow_two, ← pow_mul,
    two_mul, pow_add, ← hc, ← h1]
theorem intPow_negOfNat_bit1 (h1 : Nat.pow a b' = c')
    (hb : nat_lit 2 * b' + nat_lit 1 = b) (hc : c' * (c' * a) = c) :
    Int.pow (Int.negOfNat a) b = Int.negOfNat c := by
  rw [← hb, Int.negOfNat_eq, Int.negOfNat_eq, pow_eq, pow_succ, pow_mul, neg_pow_two, ← pow_mul,
    two_mul, pow_add, ← hc, ← h1]
  

Proof state:
a b' : ℕ
c' b c : ℕ
h1 : Nat.pow a b' = c'
hb : 2 * b' + 1 = b
hc : c' * (c' * a) = c
⊢ -Int.ofNat a * (Int.ofNat a ^ b' * Int.ofNat a ^ b') = -Int.ofNat (Nat.pow a b' * (Nat.pow a b' * a))

Next tactic:
simp [mul_assoc, mul_comm, mul_left_comm]
theorem isNat_pow {α} [Semiring α] : ∀ {f : α → ℕ → α} {a : α} {b a' b' c : ℕ},
    f = HPow.hPow → IsNat a a' → IsNat b b' → Nat.pow a' b' = c → IsNat (f a b) c
  | _, _, _, _, _, _, rfl, ⟨rfl⟩, ⟨rfl⟩, rfl => ⟨by 

Proof state:
α : Type u_1
inst✝ : Semiring α
n✝¹ n✝ : ℕ
⊢ ↑n✝¹ ^ ↑n✝ = ↑(Nat.pow n✝¹ n✝)

Next tactic:
simp
theorem isInt_pow {α} [Ring α] : ∀ {f : α → ℕ → α} {a : α} {b : ℕ} {a' : ℤ} {b' : ℕ} {c : ℤ},
    f = HPow.hPow → IsInt a a' → IsNat b b' → Int.pow a' b' = c → IsInt (f a b) c
  | _, _, _, _, _, _, rfl, ⟨rfl⟩, ⟨rfl⟩, rfl => ⟨by 

Proof state:
α : Type u_1
inst✝ : Ring α
n✝¹ : ℤ
n✝ : ℕ
⊢ ↑n✝¹ ^ ↑n✝ = ↑(Int.pow n✝¹ n✝)

Next tactic:
simp
theorem isRat_pow {α} [Ring α] {f : α → ℕ → α} {a : α} {an cn : ℤ} {ad b b' cd : ℕ} :
    f = HPow.hPow → IsRat a an ad → IsNat b b' →
    Int.pow an b' = cn → Nat.pow ad b' = cd →
    IsRat (f a b) cn cd := by
  

Proof state:
α : Type u_1
inst✝ : Ring α
f : α → ℕ → α
a : α
an cn : ℤ
ad b b' cd : ℕ
⊢ f = HPow.hPow → IsRat a an ad → IsNat b b' → Int.pow an b' = cn → Nat.pow ad b' = cd → IsRat (f a b) cn cd

Next tactic:
rintro rfl ⟨_, rfl⟩ ⟨rfl⟩ (rfl : an ^ b = _) (rfl : ad ^ b = _)
theorem isRat_pow {α} [Ring α] {f : α → ℕ → α} {a : α} {an cn : ℤ} {ad b b' cd : ℕ} :
    f = HPow.hPow → IsRat a an ad → IsNat b b' →
    Int.pow an b' = cn → Nat.pow ad b' = cd →
    IsRat (f a b) cn cd := by
  rintro rfl ⟨_, rfl⟩ ⟨rfl⟩ (rfl : an ^ b = _) (rfl : ad ^ b = _)
  

Proof state:
case mk.mk
α : Type u_1
inst✝ : Ring α
an : ℤ
ad b : ℕ
inv✝ : Invertible ↑ad
⊢ IsRat ((↑an * ⅟↑ad) ^ b) (an ^ b) (ad ^ b)

Next tactic:
have := invertiblePow (ad:α) b
theorem isRat_pow {α} [Ring α] {f : α → ℕ → α} {a : α} {an cn : ℤ} {ad b b' cd : ℕ} :
    f = HPow.hPow → IsRat a an ad → IsNat b b' →
    Int.pow an b' = cn → Nat.pow ad b' = cd →
    IsRat (f a b) cn cd := by
  rintro rfl ⟨_, rfl⟩ ⟨rfl⟩ (rfl : an ^ b = _) (rfl : ad ^ b = _)
  have := invertiblePow (ad:α) b
  

Proof state:
case mk.mk
α : Type u_1
inst✝ : Ring α
an : ℤ
ad b : ℕ
inv✝ : Invertible ↑ad
this : Invertible (↑ad ^ b)
⊢ IsRat ((↑an * ⅟↑ad) ^ b) (an ^ b) (ad ^ b)

Next tactic:
rw [← Nat.cast_pow] at this
theorem isRat_pow {α} [Ring α] {f : α → ℕ → α} {a : α} {an cn : ℤ} {ad b b' cd : ℕ} :
    f = HPow.hPow → IsRat a an ad → IsNat b b' →
    Int.pow an b' = cn → Nat.pow ad b' = cd →
    IsRat (f a b) cn cd := by
  rintro rfl ⟨_, rfl⟩ ⟨rfl⟩ (rfl : an ^ b = _) (rfl : ad ^ b = _)
  have := invertiblePow (ad:α) b
  rw [← Nat.cast_pow] at this
  

Proof state:
case mk.mk
α : Type u_1
inst✝ : Ring α
an : ℤ
ad b : ℕ
inv✝ : Invertible ↑ad
this : Invertible ↑(ad ^ b)
⊢ IsRat ((↑an * ⅟↑ad) ^ b) (an ^ b) (ad ^ b)

Next tactic:
use this
theorem isRat_pow {α} [Ring α] {f : α → ℕ → α} {a : α} {an cn : ℤ} {ad b b' cd : ℕ} :
    f = HPow.hPow → IsRat a an ad → IsNat b b' →
    Int.pow an b' = cn → Nat.pow ad b' = cd →
    IsRat (f a b) cn cd := by
  rintro rfl ⟨_, rfl⟩ ⟨rfl⟩ (rfl : an ^ b = _) (rfl : ad ^ b = _)
  have := invertiblePow (ad:α) b
  rw [← Nat.cast_pow] at this
  use this; 

Proof state:
case eq
α : Type u_1
inst✝ : Ring α
an : ℤ
ad b : ℕ
inv✝ : Invertible ↑ad
this : Invertible ↑(ad ^ b)
⊢ (↑an * ⅟↑ad) ^ b = ↑(an ^ b) * ⅟↑(ad ^ b)

Next tactic:
simp [invOf_pow, Commute.mul_pow]
@[refl]
theorem BlankExtends.refl {Γ} [Inhabited Γ] (l : List Γ) : BlankExtends l l :=
  ⟨0, by 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : List Γ
⊢ l = l ++ List.replicate 0 default

Next tactic:
simp
@[trans]
theorem BlankExtends.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankExtends l₁ l₂ → BlankExtends l₂ l₃ → BlankExtends l₁ l₃ := by
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
⊢ BlankExtends l₁ l₂ → BlankExtends l₂ l₃ → BlankExtends l₁ l₃

Next tactic:
rintro ⟨i, rfl⟩ ⟨j, rfl⟩
@[trans]
theorem BlankExtends.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankExtends l₁ l₂ → BlankExtends l₂ l₃ → BlankExtends l₁ l₃ := by
  rintro ⟨i, rfl⟩ ⟨j, rfl⟩
  

Proof state:
case intro.intro
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ : List Γ
i j : ℕ
⊢ BlankExtends l₁ (l₁ ++ List.replicate i default ++ List.replicate j default)

Next tactic:
exact ⟨i + j, by simp [List.replicate_add]⟩
@[trans]
theorem BlankExtends.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankExtends l₁ l₂ → BlankExtends l₂ l₃ → BlankExtends l₁ l₃ := by
  rintro ⟨i, rfl⟩ ⟨j, rfl⟩
  exact ⟨i + j, by 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ : List Γ
i j : ℕ
⊢ l₁ ++ List.replicate i default ++ List.replicate j default = l₁ ++ List.replicate (i + j) default

Next tactic:
simp [List.replicate_add]
theorem BlankExtends.below_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l l₁ → BlankExtends l l₂ → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l l₁ l₂ : List Γ
⊢ BlankExtends l l₁ → BlankExtends l l₂ → List.length l₁ ≤ List.length l₂ → BlankExtends l₁ l₂

Next tactic:
rintro ⟨i, rfl⟩ ⟨j, rfl⟩ h
theorem BlankExtends.below_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l l₁ → BlankExtends l l₂ → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, rfl⟩ h; 

Proof state:
case intro.intro
Γ : Type u_1
inst✝ : Inhabited Γ
l : List Γ
i j : ℕ
h : List.length (l ++ List.replicate i default) ≤ List.length (l ++ List.replicate j default)
⊢ BlankExtends (l ++ List.replicate i default) (l ++ List.replicate j default)

Next tactic:
use j - i
theorem BlankExtends.below_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l l₁ → BlankExtends l l₂ → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, rfl⟩ h; use j - i
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l : List Γ
i j : ℕ
h : List.length (l ++ List.replicate i default) ≤ List.length (l ++ List.replicate j default)
⊢ l ++ List.replicate j default = l ++ List.replicate i default ++ List.replicate (j - i) default

Next tactic:
simp only [List.length_append, add_le_add_iff_left, List.length_replicate] at h
theorem BlankExtends.below_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l l₁ → BlankExtends l l₂ → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, rfl⟩ h; use j - i
  simp only [List.length_append, add_le_add_iff_left, List.length_replicate] at h
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l : List Γ
i j : ℕ
h : i ≤ j
⊢ l ++ List.replicate j default = l ++ List.replicate i default ++ List.replicate (j - i) default

Next tactic:
simp only [← List.replicate_add, add_tsub_cancel_of_le h, List.append_assoc]
theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l l₁ l₂ : List Γ
⊢ BlankExtends l₁ l → BlankExtends l₂ l → List.length l₁ ≤ List.length l₂ → BlankExtends l₁ l₂

Next tactic:
rintro ⟨i, rfl⟩ ⟨j, e⟩ h
theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, e⟩ h; 

Proof state:
case intro.intro
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
i j : ℕ
e : l₁ ++ List.replicate i default = l₂ ++ List.replicate j default
h : List.length l₁ ≤ List.length l₂
⊢ BlankExtends l₁ l₂

Next tactic:
use i - j
theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, e⟩ h; use i - j
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
i j : ℕ
e : l₁ ++ List.replicate i default = l₂ ++ List.replicate j default
h : List.length l₁ ≤ List.length l₂
⊢ l₂ = l₁ ++ List.replicate (i - j) default

Next tactic:
refine' List.append_right_cancel (e.symm.trans _)
theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, e⟩ h; use i - j
  refine' List.append_right_cancel (e.symm.trans _)
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
i j : ℕ
e : l₁ ++ List.replicate i default = l₂ ++ List.replicate j default
h : List.length l₁ ≤ List.length l₂
⊢ l₁ ++ List.replicate i default = l₁ ++ List.replicate (i - j) default ++ List.replicate j default

Next tactic:
rw [List.append_assoc, ← List.replicate_add, tsub_add_cancel_of_le]
theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, e⟩ h; use i - j
  refine' List.append_right_cancel (e.symm.trans _)
  rw [List.append_assoc, ← List.replicate_add, tsub_add_cancel_of_le]
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
i j : ℕ
e : l₁ ++ List.replicate i default = l₂ ++ List.replicate j default
h : List.length l₁ ≤ List.length l₂
⊢ j ≤ i

Next tactic:
apply_fun List.length at e
theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, e⟩ h; use i - j
  refine' List.append_right_cancel (e.symm.trans _)
  rw [List.append_assoc, ← List.replicate_add, tsub_add_cancel_of_le]
  apply_fun List.length at e
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
i j : ℕ
h : List.length l₁ ≤ List.length l₂
e : List.length (l₁ ++ List.replicate i default) = List.length (l₂ ++ List.replicate j default)
⊢ j ≤ i

Next tactic:
simp only [List.length_append, List.length_replicate] at e
theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ := by
  rintro ⟨i, rfl⟩ ⟨j, e⟩ h; use i - j
  refine' List.append_right_cancel (e.symm.trans _)
  rw [List.append_assoc, ← List.replicate_add, tsub_add_cancel_of_le]
  apply_fun List.length at e
  simp only [List.length_append, List.length_replicate] at e
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
i j : ℕ
h : List.length l₁ ≤ List.length l₂
e : List.length l₁ + i = List.length l₂ + j
⊢ j ≤ i

Next tactic:
rwa [← add_le_add_iff_left, e, add_le_add_iff_right]
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
⊢ BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃

Next tactic:
rintro (h₁ | h₁) (h₂ | h₂)
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · 

Proof state:
case inl.inl
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₁ l₂
h₂ : BlankExtends l₂ l₃
⊢ BlankRel l₁ l₃

Next tactic:
exact Or.inl (h₁.trans h₂)
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · exact Or.inl (h₁.trans h₂)
  · 

Proof state:
case inl.inr
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₁ l₂
h₂ : BlankExtends l₃ l₂
⊢ BlankRel l₁ l₃

Next tactic:
rcases le_total l₁.length l₃.length with h | h
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · exact Or.inl (h₁.trans h₂)
  · rcases le_total l₁.length l₃.length with h | h
    · 

Proof state:
case inl.inr.inl
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₁ l₂
h₂ : BlankExtends l₃ l₂
h : List.length l₁ ≤ List.length l₃
⊢ BlankRel l₁ l₃

Next tactic:
exact Or.inl (h₁.above_of_le h₂ h)
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · exact Or.inl (h₁.trans h₂)
  · rcases le_total l₁.length l₃.length with h | h
    · exact Or.inl (h₁.above_of_le h₂ h)
    · 

Proof state:
case inl.inr.inr
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₁ l₂
h₂ : BlankExtends l₃ l₂
h : List.length l₃ ≤ List.length l₁
⊢ BlankRel l₁ l₃

Next tactic:
exact Or.inr (h₂.above_of_le h₁ h)
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · exact Or.inl (h₁.trans h₂)
  · rcases le_total l₁.length l₃.length with h | h
    · exact Or.inl (h₁.above_of_le h₂ h)
    · exact Or.inr (h₂.above_of_le h₁ h)
  · 

Proof state:
case inr.inl
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₂ l₁
h₂ : BlankExtends l₂ l₃
⊢ BlankRel l₁ l₃

Next tactic:
rcases le_total l₁.length l₃.length with h | h
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · exact Or.inl (h₁.trans h₂)
  · rcases le_total l₁.length l₃.length with h | h
    · exact Or.inl (h₁.above_of_le h₂ h)
    · exact Or.inr (h₂.above_of_le h₁ h)
  · rcases le_total l₁.length l₃.length with h | h
    · 

Proof state:
case inr.inl.inl
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₂ l₁
h₂ : BlankExtends l₂ l₃
h : List.length l₁ ≤ List.length l₃
⊢ BlankRel l₁ l₃

Next tactic:
exact Or.inl (h₁.below_of_le h₂ h)
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · exact Or.inl (h₁.trans h₂)
  · rcases le_total l₁.length l₃.length with h | h
    · exact Or.inl (h₁.above_of_le h₂ h)
    · exact Or.inr (h₂.above_of_le h₁ h)
  · rcases le_total l₁.length l₃.length with h | h
    · exact Or.inl (h₁.below_of_le h₂ h)
    · 

Proof state:
case inr.inl.inr
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₂ l₁
h₂ : BlankExtends l₂ l₃
h : List.length l₃ ≤ List.length l₁
⊢ BlankRel l₁ l₃

Next tactic:
exact Or.inr (h₂.below_of_le h₁ h)
@[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ := by
  rintro (h₁ | h₁) (h₂ | h₂)
  · exact Or.inl (h₁.trans h₂)
  · rcases le_total l₁.length l₃.length with h | h
    · exact Or.inl (h₁.above_of_le h₂ h)
    · exact Or.inr (h₂.above_of_le h₁ h)
  · rcases le_total l₁.length l₃.length with h | h
    · exact Or.inl (h₁.below_of_le h₂ h)
    · exact Or.inr (h₂.below_of_le h₁ h)
  · 

Proof state:
case inr.inr
Γ : Type u_1
inst✝ : Inhabited Γ
l₁ l₂ l₃ : List Γ
h₁ : BlankExtends l₂ l₁
h₂ : BlankExtends l₃ l₂
⊢ BlankRel l₁ l₃

Next tactic:
exact Or.inr (h₂.trans h₁)
/-- Given two `BlankRel` lists, there exists (constructively) a common join. -/
def BlankRel.above {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l₁ l ∧ BlankExtends l₂ l } := by
  

Proof state:
Γ : Type ?u.9819
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
⊢ { l // BlankExtends l₁ l ∧ BlankExtends l₂ l }

Next tactic:
refine'
    if hl : l₁.length ≤ l₂.length then ⟨l₂, Or.elim h id fun h' ↦ _, BlankExtends.refl _⟩
    else ⟨l₁, BlankExtends.refl _, Or.elim h (fun h' ↦ _) id⟩
/-- Given two `BlankRel` lists, there exists (constructively) a common join. -/
def BlankRel.above {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l₁ l ∧ BlankExtends l₂ l } := by
  refine'
    if hl : l₁.length ≤ l₂.length then ⟨l₂, Or.elim h id fun h' ↦ _, BlankExtends.refl _⟩
    else ⟨l₁, BlankExtends.refl _, Or.elim h (fun h' ↦ _) id⟩
  

Proof state:
case refine'_1
Γ : Type ?u.9819
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
hl : List.length l₁ ≤ List.length l₂
h' : BlankExtends l₂ l₁
⊢ BlankExtends l₁ l₂
case refine'_2
Γ : Type ?u.9819
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
hl : ¬List.length l₁ ≤ List.length l₂
h' : BlankExtends l₁ l₂
⊢ BlankExtends l₂ l₁

Next tactic:
exact (BlankExtends.refl _).above_of_le h' hl