l3lab/ntp-mathlib huggingface dataset:
/-- The additive monoid morphism `dyadicMap` sends ⟦⟨m, 2^n⟩⟧ to m • half ^ n. -/
def dyadicMap : Localization.Away (2 : ℤ) →+ Surreal where
  toFun x :=
    (Localization.liftOn x fun x y => x • powHalf (Submonoid.log y)) <| by
      intro m₁ m₂ n₁ n₂ h₁
      obtain ⟨⟨n₃, y₃, hn₃⟩, h₂⟩ := Localization.r_iff_exists.mp h₁
      simp only [Subtype.coe_mk, mul_eq_mul_left_iff] at h₂
      cases h₂
      · obtain ⟨a₁, ha₁⟩ := n₁.prop
        obtain ⟨a₂, ha₂⟩ := n₂.prop
        simp only at ha₁ ha₂ ⊢
        have hn₁ : n₁ = Submonoid.pow 2 a₁ := Subtype.ext ha₁.symm
        have hn₂ : n₂ = Submonoid.pow 2 a₂ := Subtype.ext ha₂.symm
        have h₂ : 1 < (2 : ℤ).natAbs := one_lt_two
        rw [hn₁, hn₂, Submonoid.log_pow_int_eq_self h₂, Submonoid.log_pow_int_eq_self h₂]
        apply dyadic_aux
        rwa [ha₁, ha₂, mul_comm, mul_comm m₂]
      · have : (1 : ℤ) ≤ 2 ^ y₃ := mod_cast Nat.one_le_pow y₃ 2 Nat.succ_pos'
        

Proof state:
case intro.mk.intro.inr
x : Localization.Away 2
m₁ m₂ : ℤ
n₁ n₂ : ↥(Submonoid.powers 2)
h₁ : (Localization.r (Submonoid.powers 2)) (m₁, n₁) (m₂, n₂)
n₃ : ℤ
y₃ : ℕ
hn₃ : (fun x => 2 ^ x) y₃ = n₃
h✝ : n₃ = 0
this : 1 ≤ 2 ^ y₃
⊢ m₁ • powHalf (Submonoid.log n₁) = m₂ • powHalf (Submonoid.log n₂)

Next tactic:
linarith
/-- The additive monoid morphism `dyadicMap` sends ⟦⟨m, 2^n⟩⟧ to m • half ^ n. -/
def dyadicMap : Localization.Away (2 : ℤ) →+ Surreal where
  toFun x :=
    (Localization.liftOn x fun x y => x • powHalf (Submonoid.log y)) <| by
      intro m₁ m₂ n₁ n₂ h₁
      obtain ⟨⟨n₃, y₃, hn₃⟩, h₂⟩ := Localization.r_iff_exists.mp h₁
      simp only [Subtype.coe_mk, mul_eq_mul_left_iff] at h₂
      cases h₂
      · obtain ⟨a₁, ha₁⟩ := n₁.prop
        obtain ⟨a₂, ha₂⟩ := n₂.prop
        simp only at ha₁ ha₂ ⊢
        have hn₁ : n₁ = Submonoid.pow 2 a₁ := Subtype.ext ha₁.symm
        have hn₂ : n₂ = Submonoid.pow 2 a₂ := Subtype.ext ha₂.symm
        have h₂ : 1 < (2 : ℤ).natAbs := one_lt_two
        rw [hn₁, hn₂, Submonoid.log_pow_int_eq_self h₂, Submonoid.log_pow_int_eq_self h₂]
        apply dyadic_aux
        rwa [ha₁, ha₂, mul_comm, mul_comm m₂]
      · have : (1 : ℤ) ≤ 2 ^ y₃ := mod_cast Nat.one_le_pow y₃ 2 Nat.succ_pos'
        linarith
  map_zero' := Localization.liftOn_zero _ _
  map_add' x y :=
    Localization.induction_on₂ x y <| by
      rintro ⟨a, ⟨b, ⟨b', rfl⟩⟩⟩ ⟨c, ⟨d, ⟨d', rfl⟩⟩⟩
      have h₂ : 1 < (2 : ℤ).natAbs := one_lt_two
      have hpow₂ := Submonoid.log_pow_int_eq_self h₂
      simp_rw [Submonoid.pow_apply] at hpow₂
      simp_rw [Localization.add_mk, Localization.liftOn_mk,
        Submonoid.log_mul (Int.pow_right_injective h₂), hpow₂]
      

Proof state:
case mk.mk.intro.mk.mk.intro
x y : Localization.Away 2
a : ℤ
b' : ℕ
c : ℤ
d' : ℕ
h₂ : 1 < Int.natAbs 2
hpow₂ : ∀ (m : ℕ), Submonoid.log { val := 2 ^ m, property := (_ : ∃ y, (fun x => 2 ^ x) y = 2 ^ m) } = m
⊢ (2 ^ b' * c + 2 ^ d' * a) • powHalf (b' + d') = a • powHalf b' + c • powHalf d'

Next tactic:
calc
        (2 ^ b' * c + 2 ^ d' * a) • powHalf (b' + d') =
            (c * 2 ^ b') • powHalf (b' + d') + (a * 2 ^ d') • powHalf (d' + b') := by
          simp only [add_smul, mul_comm, add_comm]
        _ = c • powHalf d' + a • powHalf b' := by simp only [zsmul_pow_two_powHalf]
        _ = a • powHalf b' + c • powHalf d' := add_comm _ _
/-- The additive monoid morphism `dyadicMap` sends ⟦⟨m, 2^n⟩⟧ to m • half ^ n. -/
def dyadicMap : Localization.Away (2 : ℤ) →+ Surreal where
  toFun x :=
    (Localization.liftOn x fun x y => x • powHalf (Submonoid.log y)) <| by
      intro m₁ m₂ n₁ n₂ h₁
      obtain ⟨⟨n₃, y₃, hn₃⟩, h₂⟩ := Localization.r_iff_exists.mp h₁
      simp only [Subtype.coe_mk, mul_eq_mul_left_iff] at h₂
      cases h₂
      · obtain ⟨a₁, ha₁⟩ := n₁.prop
        obtain ⟨a₂, ha₂⟩ := n₂.prop
        simp only at ha₁ ha₂ ⊢
        have hn₁ : n₁ = Submonoid.pow 2 a₁ := Subtype.ext ha₁.symm
        have hn₂ : n₂ = Submonoid.pow 2 a₂ := Subtype.ext ha₂.symm
        have h₂ : 1 < (2 : ℤ).natAbs := one_lt_two
        rw [hn₁, hn₂, Submonoid.log_pow_int_eq_self h₂, Submonoid.log_pow_int_eq_self h₂]
        apply dyadic_aux
        rwa [ha₁, ha₂, mul_comm, mul_comm m₂]
      · have : (1 : ℤ) ≤ 2 ^ y₃ := mod_cast Nat.one_le_pow y₃ 2 Nat.succ_pos'
        linarith
  map_zero' := Localization.liftOn_zero _ _
  map_add' x y :=
    Localization.induction_on₂ x y <| by
      rintro ⟨a, ⟨b, ⟨b', rfl⟩⟩⟩ ⟨c, ⟨d, ⟨d', rfl⟩⟩⟩
      have h₂ : 1 < (2 : ℤ).natAbs := one_lt_two
      have hpow₂ := Submonoid.log_pow_int_eq_self h₂
      simp_rw [Submonoid.pow_apply] at hpow₂
      simp_rw [Localization.add_mk, Localization.liftOn_mk,
        Submonoid.log_mul (Int.pow_right_injective h₂), hpow₂]
      calc
        (2 ^ b' * c + 2 ^ d' * a) • powHalf (b' + d') =
            (c * 2 ^ b') • powHalf (b' + d') + (a * 2 ^ d') • powHalf (d' + b') := by
          

Proof state:
x y : Localization.Away 2
a : ℤ
b' : ℕ
c : ℤ
d' : ℕ
h₂ : 1 < Int.natAbs 2
hpow₂ : ∀ (m : ℕ), Submonoid.log { val := 2 ^ m, property := (_ : ∃ y, (fun x => 2 ^ x) y = 2 ^ m) } = m
⊢ (2 ^ b' * c + 2 ^ d' * a) • powHalf (b' + d') = (c * 2 ^ b') • powHalf (b' + d') + (a * 2 ^ d') • powHalf (d' + b')

Next tactic:
simp only [add_smul, mul_comm, add_comm]
/-- The additive monoid morphism `dyadicMap` sends ⟦⟨m, 2^n⟩⟧ to m • half ^ n. -/
def dyadicMap : Localization.Away (2 : ℤ) →+ Surreal where
  toFun x :=
    (Localization.liftOn x fun x y => x • powHalf (Submonoid.log y)) <| by
      intro m₁ m₂ n₁ n₂ h₁
      obtain ⟨⟨n₃, y₃, hn₃⟩, h₂⟩ := Localization.r_iff_exists.mp h₁
      simp only [Subtype.coe_mk, mul_eq_mul_left_iff] at h₂
      cases h₂
      · obtain ⟨a₁, ha₁⟩ := n₁.prop
        obtain ⟨a₂, ha₂⟩ := n₂.prop
        simp only at ha₁ ha₂ ⊢
        have hn₁ : n₁ = Submonoid.pow 2 a₁ := Subtype.ext ha₁.symm
        have hn₂ : n₂ = Submonoid.pow 2 a₂ := Subtype.ext ha₂.symm
        have h₂ : 1 < (2 : ℤ).natAbs := one_lt_two
        rw [hn₁, hn₂, Submonoid.log_pow_int_eq_self h₂, Submonoid.log_pow_int_eq_self h₂]
        apply dyadic_aux
        rwa [ha₁, ha₂, mul_comm, mul_comm m₂]
      · have : (1 : ℤ) ≤ 2 ^ y₃ := mod_cast Nat.one_le_pow y₃ 2 Nat.succ_pos'
        linarith
  map_zero' := Localization.liftOn_zero _ _
  map_add' x y :=
    Localization.induction_on₂ x y <| by
      rintro ⟨a, ⟨b, ⟨b', rfl⟩⟩⟩ ⟨c, ⟨d, ⟨d', rfl⟩⟩⟩
      have h₂ : 1 < (2 : ℤ).natAbs := one_lt_two
      have hpow₂ := Submonoid.log_pow_int_eq_self h₂
      simp_rw [Submonoid.pow_apply] at hpow₂
      simp_rw [Localization.add_mk, Localization.liftOn_mk,
        Submonoid.log_mul (Int.pow_right_injective h₂), hpow₂]
      calc
        (2 ^ b' * c + 2 ^ d' * a) • powHalf (b' + d') =
            (c * 2 ^ b') • powHalf (b' + d') + (a * 2 ^ d') • powHalf (d' + b') := by
          simp only [add_smul, mul_comm, add_comm]
        _ = c • powHalf d' + a • powHalf b' := by 

Proof state:
x y : Localization.Away 2
a : ℤ
b' : ℕ
c : ℤ
d' : ℕ
h₂ : 1 < Int.natAbs 2
hpow₂ : ∀ (m : ℕ), Submonoid.log { val := 2 ^ m, property := (_ : ∃ y, (fun x => 2 ^ x) y = 2 ^ m) } = m
⊢ (c * 2 ^ b') • powHalf (b' + d') + (a * 2 ^ d') • powHalf (d' + b') = c • powHalf d' + a • powHalf b'

Next tactic:
simp only [zsmul_pow_two_powHalf]
@[simp]
theorem dyadicMap_apply (m : ℤ) (p : Submonoid.powers (2 : ℤ)) :
    dyadicMap (IsLocalization.mk' (Localization (Submonoid.powers 2)) m p) =
      m • powHalf (Submonoid.log p) := by
  

Proof state:
m : ℤ
p : ↥(Submonoid.powers 2)
⊢ dyadicMap (IsLocalization.mk' (Localization (Submonoid.powers 2)) m p) = m • powHalf (Submonoid.log p)

Next tactic:
rw [← Localization.mk_eq_mk']
@[simp]
theorem dyadicMap_apply (m : ℤ) (p : Submonoid.powers (2 : ℤ)) :
    dyadicMap (IsLocalization.mk' (Localization (Submonoid.powers 2)) m p) =
      m • powHalf (Submonoid.log p) := by
  rw [← Localization.mk_eq_mk']; 

Proof state:
m : ℤ
p : ↥(Submonoid.powers 2)
⊢ dyadicMap (Localization.mk m p) = m • powHalf (Submonoid.log p)

Next tactic:
rfl
theorem dyadicMap_apply_pow (m : ℤ) (n : ℕ) :
    dyadicMap (IsLocalization.mk' (Localization (Submonoid.powers 2)) m (Submonoid.pow 2 n)) =
      m • powHalf n := by
  

Proof state:
m : ℤ
n : ℕ
⊢ dyadicMap (IsLocalization.mk' (Localization (Submonoid.powers 2)) m (Submonoid.pow 2 n)) = m • powHalf n

Next tactic:
rw [dyadicMap_apply, @Submonoid.log_pow_int_eq_self 2 one_lt_two]
@[simp]
theorem dyadicMap_apply_pow' (m : ℤ) (n : ℕ) :
    m • Surreal.powHalf (Submonoid.log (Submonoid.pow (2 : ℤ) n)) = m • powHalf n := by
  

Proof state:
m : ℤ
n : ℕ
⊢ m • powHalf (Submonoid.log (Submonoid.pow 2 n)) = m • powHalf n

Next tactic:
rw [@Submonoid.log_pow_int_eq_self 2 one_lt_two]
@[simp]
theorem encode_ofNat (n) : encode (ofNat α n) = n := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ encode (ofNat α n) = n

Next tactic:
obtain ⟨a, h, e⟩ := decode_inv (α := α) n
@[simp]
theorem encode_ofNat (n) : encode (ofNat α n) = n := by
  obtain ⟨a, h, e⟩ := decode_inv (α := α) n
  

Proof state:
case intro.intro
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
a : α
h : a ∈ decode n
e : encode a = n
⊢ encode (ofNat α n) = n

Next tactic:
rwa [ofNat_of_decode h]
/-- Denumerability is conserved by equivalences. This is transitivity of equivalence the denumerable
way. -/
def ofEquiv (α) {β} [Denumerable α] (e : β ≃ α) : Denumerable β :=
  { Encodable.ofEquiv _ e with
    decode_inv := fun n => by
      -- Porting note: replaced `simp`
      

Proof state:
α✝ : Type u_1
β✝ : Type u_2
inst✝² : Denumerable α✝
inst✝¹ : Denumerable β✝
α : Type ?u.1570
β : Type ?u.1577
inst✝ : Denumerable α
e : β ≃ α
src✝ : Encodable β := Encodable.ofEquiv α e
n : ℕ
⊢ ∃ a ∈ decode n, encode a = n

Next tactic:
simp_rw [Option.mem_def, decode_ofEquiv e, encode_ofEquiv e, decode_eq_ofNat,
        Option.map_some', Option.some_inj, exists_eq_left', Equiv.apply_symm_apply,
        Denumerable.encode_ofNat]
@[simp]
theorem ofEquiv_ofNat (α) {β} [Denumerable α] (e : β ≃ α) (n) :
    @ofNat β (ofEquiv _ e) n = e.symm (ofNat α n) := by
  -- Porting note: added `letI`
  

Proof state:
α✝ : Type u_1
β✝ : Type u_2
inst✝² : Denumerable α✝
inst✝¹ : Denumerable β✝
α : Type u_3
β : Type u_4
inst✝ : Denumerable α
e : β ≃ α
n : ℕ
⊢ ofNat β n = e.symm (ofNat α n)

Next tactic:
letI := ofEquiv _ e
@[simp]
theorem ofEquiv_ofNat (α) {β} [Denumerable α] (e : β ≃ α) (n) :
    @ofNat β (ofEquiv _ e) n = e.symm (ofNat α n) := by
  -- Porting note: added `letI`
  letI := ofEquiv _ e
  

Proof state:
α✝ : Type u_1
β✝ : Type u_2
inst✝² : Denumerable α✝
inst✝¹ : Denumerable β✝
α : Type u_3
β : Type u_4
inst✝ : Denumerable α
e : β ≃ α
n : ℕ
this : Denumerable β := ofEquiv α e
⊢ ofNat β n = e.symm (ofNat α n)

Next tactic:
refine ofNat_of_decode ?_
@[simp]
theorem ofEquiv_ofNat (α) {β} [Denumerable α] (e : β ≃ α) (n) :
    @ofNat β (ofEquiv _ e) n = e.symm (ofNat α n) := by
  -- Porting note: added `letI`
  letI := ofEquiv _ e
  refine ofNat_of_decode ?_
  

Proof state:
α✝ : Type u_1
β✝ : Type u_2
inst✝² : Denumerable α✝
inst✝¹ : Denumerable β✝
α : Type u_3
β : Type u_4
inst✝ : Denumerable α
e : β ≃ α
n : ℕ
this : Denumerable β := ofEquiv α e
⊢ decode n = some (e.symm (ofNat α n))

Next tactic:
rw [decode_ofEquiv e]
@[simp]
theorem ofEquiv_ofNat (α) {β} [Denumerable α] (e : β ≃ α) (n) :
    @ofNat β (ofEquiv _ e) n = e.symm (ofNat α n) := by
  -- Porting note: added `letI`
  letI := ofEquiv _ e
  refine ofNat_of_decode ?_
  rw [decode_ofEquiv e]
  

Proof state:
α✝ : Type u_1
β✝ : Type u_2
inst✝² : Denumerable α✝
inst✝¹ : Denumerable β✝
α : Type u_3
β : Type u_4
inst✝ : Denumerable α
e : β ≃ α
n : ℕ
this : Denumerable β := ofEquiv α e
⊢ Option.map (⇑e.symm) (decode n) = some (e.symm (ofNat α n))

Next tactic:
simp
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ ∃ a ∈ decode n, encode a = n

Next tactic:
cases n
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    

Proof state:
case zero
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
⊢ ∃ a ∈ decode zero, encode a = zero
case succ
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n✝ : ℕ
⊢ ∃ a ∈ decode (succ n✝), encode a = succ n✝

Next tactic:
case zero =>
      refine' ⟨none, _, encode_none⟩
      rw [decode_option_zero, Option.mem_def]
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
⊢ ∃ a ∈ decode zero, encode a = zero

Next tactic:
case zero =>
      refine' ⟨none, _, encode_none⟩
      rw [decode_option_zero, Option.mem_def]
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    case zero =>
      

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
⊢ ∃ a ∈ decode zero, encode a = zero

Next tactic:
refine' ⟨none, _, encode_none⟩
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    case zero =>
      refine' ⟨none, _, encode_none⟩
      

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
⊢ none ∈ decode zero

Next tactic:
rw [decode_option_zero, Option.mem_def]
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    case zero =>
      refine' ⟨none, _, encode_none⟩
      rw [decode_option_zero, Option.mem_def]
    

Proof state:
case succ
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n✝ : ℕ
⊢ ∃ a ∈ decode (succ n✝), encode a = succ n✝

Next tactic:
case succ n =>
      refine' ⟨some (ofNat α n), _, _⟩
      · rw [decode_option_succ, decode_eq_ofNat, Option.map_some', Option.mem_def]
      rw [encode_some, encode_ofNat]
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    case zero =>
      refine' ⟨none, _, encode_none⟩
      rw [decode_option_zero, Option.mem_def]
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ ∃ a ∈ decode (succ n), encode a = succ n

Next tactic:
case succ n =>
      refine' ⟨some (ofNat α n), _, _⟩
      · rw [decode_option_succ, decode_eq_ofNat, Option.map_some', Option.mem_def]
      rw [encode_some, encode_ofNat]
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    case zero =>
      refine' ⟨none, _, encode_none⟩
      rw [decode_option_zero, Option.mem_def]
    case succ n =>
      

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ ∃ a ∈ decode (succ n), encode a = succ n

Next tactic:
refine' ⟨some (ofNat α n), _, _⟩
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    case zero =>
      refine' ⟨none, _, encode_none⟩
      rw [decode_option_zero, Option.mem_def]
    case succ n =>
      refine' ⟨some (ofNat α n), _, _⟩
      · 

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ some (ofNat α n) ∈ decode (succ n)

Next tactic:
rw [decode_option_succ, decode_eq_ofNat, Option.map_some', Option.mem_def]
/-- If `α` is denumerable, then so is `Option α`. -/
instance option : Denumerable (Option α) :=
  ⟨fun n => by
    cases n
    case zero =>
      refine' ⟨none, _, encode_none⟩
      rw [decode_option_zero, Option.mem_def]
    case succ n =>
      refine' ⟨some (ofNat α n), _, _⟩
      · rw [decode_option_succ, decode_eq_ofNat, Option.map_some', Option.mem_def]
      

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ encode (some (ofNat α n)) = succ n

Next tactic:
rw [encode_some, encode_ofNat]
set_option linter.deprecated false in
/-- If `α` and `β` are denumerable, then so is their sum. -/
instance sum : Denumerable (Sum α β) :=
  ⟨fun n => by
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ ∃ a ∈ decode n, encode a = n

Next tactic:
suffices ∃ a ∈ @decodeSum α β _ _ n, encodeSum a = bit (bodd n) (div2 n) by simpa [bit_decomp]
set_option linter.deprecated false in
/-- If `α` and `β` are denumerable, then so is their sum. -/
instance sum : Denumerable (Sum α β) :=
  ⟨fun n => by
    suffices ∃ a ∈ @decodeSum α β _ _ n, encodeSum a = bit (bodd n) (div2 n) by 

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
this : ∃ a ∈ decodeSum n, encodeSum a = bit (bodd n) (div2 n)
⊢ ∃ a ∈ decode n, encode a = n

Next tactic:
simpa [bit_decomp]
set_option linter.deprecated false in
/-- If `α` and `β` are denumerable, then so is their sum. -/
instance sum : Denumerable (Sum α β) :=
  ⟨fun n => by
    suffices ∃ a ∈ @decodeSum α β _ _ n, encodeSum a = bit (bodd n) (div2 n) by simpa [bit_decomp]
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ ∃ a ∈ decodeSum n, encodeSum a = bit (bodd n) (div2 n)

Next tactic:
simp only [decodeSum, boddDiv2_eq, decode_eq_ofNat, Option.some.injEq, Option.map_some',
      Option.mem_def, Sum.exists]
set_option linter.deprecated false in
/-- If `α` and `β` are denumerable, then so is their sum. -/
instance sum : Denumerable (Sum α β) :=
  ⟨fun n => by
    suffices ∃ a ∈ @decodeSum α β _ _ n, encodeSum a = bit (bodd n) (div2 n) by simpa [bit_decomp]
    simp only [decodeSum, boddDiv2_eq, decode_eq_ofNat, Option.some.injEq, Option.map_some',
      Option.mem_def, Sum.exists]
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ (∃ a,
      (match (bodd n, div2 n) with
          | (false, m) => some (Sum.inl (ofNat α m))
          | (fst, m) => some (Sum.inr (ofNat β m))) =
          some (Sum.inl a) ∧
        encodeSum (Sum.inl a) = bit (bodd n) (div2 n)) ∨
    ∃ b,
      (match (bodd n, div2 n) with
          | (false, m) => some (Sum.inl (ofNat α m))
          | (fst, m) => some (Sum.inr (ofNat β m))) =
          some (Sum.inr b) ∧
        encodeSum (Sum.inr b) = bit (bodd n) (div2 n)

Next tactic:
cases bodd n
set_option linter.deprecated false in
/-- If `α` and `β` are denumerable, then so is their sum. -/
instance sum : Denumerable (Sum α β) :=
  ⟨fun n => by
    suffices ∃ a ∈ @decodeSum α β _ _ n, encodeSum a = bit (bodd n) (div2 n) by simpa [bit_decomp]
    simp only [decodeSum, boddDiv2_eq, decode_eq_ofNat, Option.some.injEq, Option.map_some',
      Option.mem_def, Sum.exists]
    cases bodd n <;> 

Proof state:
case false
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ (∃ a,
      (match (false, div2 n) with
          | (false, m) => some (Sum.inl (ofNat α m))
          | (fst, m) => some (Sum.inr (ofNat β m))) =
          some (Sum.inl a) ∧
        encodeSum (Sum.inl a) = bit false (div2 n)) ∨
    ∃ b,
      (match (false, div2 n) with
          | (false, m) => some (Sum.inl (ofNat α m))
          | (fst, m) => some (Sum.inr (ofNat β m))) =
          some (Sum.inr b) ∧
        encodeSum (Sum.inr b) = bit false (div2 n)

Next tactic:
simp [decodeSum, bit, encodeSum, bit0_eq_two_mul, bit1]
set_option linter.deprecated false in
/-- If `α` and `β` are denumerable, then so is their sum. -/
instance sum : Denumerable (Sum α β) :=
  ⟨fun n => by
    suffices ∃ a ∈ @decodeSum α β _ _ n, encodeSum a = bit (bodd n) (div2 n) by simpa [bit_decomp]
    simp only [decodeSum, boddDiv2_eq, decode_eq_ofNat, Option.some.injEq, Option.map_some',
      Option.mem_def, Sum.exists]
    cases bodd n <;> 

Proof state:
case true
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ (∃ a,
      (match (true, div2 n) with
          | (false, m) => some (Sum.inl (ofNat α m))
          | (fst, m) => some (Sum.inr (ofNat β m))) =
          some (Sum.inl a) ∧
        encodeSum (Sum.inl a) = bit true (div2 n)) ∨
    ∃ b,
      (match (true, div2 n) with
          | (false, m) => some (Sum.inl (ofNat α m))
          | (fst, m) => some (Sum.inr (ofNat β m))) =
          some (Sum.inr b) ∧
        encodeSum (Sum.inr b) = bit true (div2 n)

Next tactic:
simp [decodeSum, bit, encodeSum, bit0_eq_two_mul, bit1]
/-- A denumerable collection of denumerable types is denumerable. -/
instance sigma : Denumerable (Sigma γ) :=
  ⟨fun n => by 

Proof state:
α : Type u_1
β : Type u_2
inst✝² : Denumerable α
inst✝¹ : Denumerable β
γ : α → Type u_3
inst✝ : (a : α) → Denumerable (γ a)
n : ℕ
⊢ ∃ a ∈ decode n, encode a = n

Next tactic:
simp [decodeSigma]
@[simp]
theorem sigma_ofNat_val (n : ℕ) :
    ofNat (Sigma γ) n = ⟨ofNat α (unpair n).1, ofNat (γ _) (unpair n).2⟩ :=
  Option.some.inj <| by 

Proof state:
α : Type u_1
β : Type u_2
inst✝² : Denumerable α
inst✝¹ : Denumerable β
γ : α → Type u_3
inst✝ : (a : α) → Denumerable (γ a)
n : ℕ
⊢ some (ofNat (Sigma γ) n) = some { fst := ofNat α (unpair n).1, snd := ofNat (γ (ofNat α (unpair n).1)) (unpair n).2 }

Next tactic:
rw [← decode_eq_ofNat, decode_sigma_val]
@[simp]
theorem sigma_ofNat_val (n : ℕ) :
    ofNat (Sigma γ) n = ⟨ofNat α (unpair n).1, ofNat (γ _) (unpair n).2⟩ :=
  Option.some.inj <| by rw [← decode_eq_ofNat, decode_sigma_val]; 

Proof state:
α : Type u_1
β : Type u_2
inst✝² : Denumerable α
inst✝¹ : Denumerable β
γ : α → Type u_3
inst✝ : (a : α) → Denumerable (γ a)
n : ℕ
⊢ (Option.bind (decode (unpair n).1) fun a => Option.map (Sigma.mk a) (decode (unpair n).2)) =
    some { fst := ofNat α (unpair n).1, snd := ofNat (γ (ofNat α (unpair n).1)) (unpair n).2 }

Next tactic:
simp
theorem prod_ofNat_val (n : ℕ) : ofNat (α × β) n = (ofNat α (unpair n).1, ofNat β (unpair n).2) :=
  by 

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
n : ℕ
⊢ ofNat (α × β) n = (ofNat α (unpair n).1, ofNat β (unpair n).2)

Next tactic:
simp
@[simp]
theorem prod_nat_ofNat : ofNat (ℕ × ℕ) = unpair := by 

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
⊢ ofNat (ℕ × ℕ) = unpair

Next tactic:
funext
@[simp]
theorem prod_nat_ofNat : ofNat (ℕ × ℕ) = unpair := by funext; 

Proof state:
case h
α : Type u_1
β : Type u_2
inst✝¹ : Denumerable α
inst✝ : Denumerable β
x✝ : ℕ
⊢ ofNat (ℕ × ℕ) x✝ = unpair x✝

Next tactic:
simp
theorem exists_succ (x : s) : ∃ n, (x : ℕ) + n + 1 ∈ s :=
  _root_.by_contradiction fun h =>
    have : ∀ (a : ℕ) (_ : a ∈ s), a < succ x := fun a ha =>
      lt_of_not_ge fun hax => h ⟨a - (x + 1), by 

Proof state:
α : Type u_1
β : Type u_2
s : Set ℕ
inst✝ : Infinite ↑s
x : ↑s
h : ¬∃ n, ↑x + n + 1 ∈ s
a : ℕ
ha : a ∈ s
hax : a ≥ succ ↑x
⊢ ↑x + (a - (↑x + 1)) + 1 ∈ s

Next tactic:
rwa [add_right_comm, add_tsub_cancel_of_le hax]
theorem exists_succ (x : s) : ∃ n, (x : ℕ) + n + 1 ∈ s :=
  _root_.by_contradiction fun h =>
    have : ∀ (a : ℕ) (_ : a ∈ s), a < succ x := fun a ha =>
      lt_of_not_ge fun hax => h ⟨a - (x + 1), by rwa [add_right_comm, add_tsub_cancel_of_le hax]⟩
    Fintype.false
      ⟨(((Multiset.range (succ x)).filter (· ∈ s)).pmap
            (fun (y : ℕ) (hy : y ∈ s) => Subtype.mk y hy)
            (by 

Proof state:
α : Type u_1
β : Type u_2
s : Set ℕ
inst✝ : Infinite ↑s
x : ↑s
h : ¬∃ n, ↑x + n + 1 ∈ s
this : ∀ a ∈ s, a < succ ↑x
⊢ ∀ a ∈ Multiset.filter (fun x => x ∈ s) (Multiset.range (succ ↑x)), a ∈ s

Next tactic:
simp [-Multiset.range_succ]