l3lab/ntp-mathlib huggingface dataset:
/-- If `a^(p-1) = 1 mod p`, but `a^((p-1)/q) ≠ 1 mod p` for all prime factors `q` of `p-1`, then `p`
is prime. This is true because `a` has order `p-1` in the multiplicative group mod `p`, so this
group must itself have order `p-1`, which only happens when `p` is prime.
-/
theorem lucas_primality (p : ℕ) (a : ZMod p) (ha : a ^ (p - 1) = 1)
    (hd : ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1) : p.Prime := by
  have h0 : p ≠ 0 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have h1 : p ≠ 1 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have hp1 : 1 < p := lt_of_le_of_ne h0.bot_lt h1.symm
  have order_of_a : orderOf a = p - 1 := by
    apply orderOf_eq_of_pow_and_pow_div_prime _ ha hd
    exact tsub_pos_of_lt hp1
  haveI : NeZero p := ⟨h0⟩
  rw [Nat.prime_iff_card_units]
  -- Prove cardinality of `Units` of `ZMod p` is both `≤ p-1` and `≥ p-1`
  

Proof state:
p : ℕ
a : ZMod p
ha : a ^ (p - 1) = 1
hd : ∀ (q : ℕ), Nat.Prime q → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1
h0 : p ≠ 0
h1 : p ≠ 1
hp1 : 1 < p
order_of_a : orderOf a = p - 1
this : NeZero p
⊢ Fintype.card (ZMod p)ˣ = p - 1

Next tactic:
refine' le_antisymm (Nat.card_units_zmod_lt_sub_one hp1) _
/-- If `a^(p-1) = 1 mod p`, but `a^((p-1)/q) ≠ 1 mod p` for all prime factors `q` of `p-1`, then `p`
is prime. This is true because `a` has order `p-1` in the multiplicative group mod `p`, so this
group must itself have order `p-1`, which only happens when `p` is prime.
-/
theorem lucas_primality (p : ℕ) (a : ZMod p) (ha : a ^ (p - 1) = 1)
    (hd : ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1) : p.Prime := by
  have h0 : p ≠ 0 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have h1 : p ≠ 1 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have hp1 : 1 < p := lt_of_le_of_ne h0.bot_lt h1.symm
  have order_of_a : orderOf a = p - 1 := by
    apply orderOf_eq_of_pow_and_pow_div_prime _ ha hd
    exact tsub_pos_of_lt hp1
  haveI : NeZero p := ⟨h0⟩
  rw [Nat.prime_iff_card_units]
  -- Prove cardinality of `Units` of `ZMod p` is both `≤ p-1` and `≥ p-1`
  refine' le_antisymm (Nat.card_units_zmod_lt_sub_one hp1) _
  

Proof state:
p : ℕ
a : ZMod p
ha : a ^ (p - 1) = 1
hd : ∀ (q : ℕ), Nat.Prime q → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1
h0 : p ≠ 0
h1 : p ≠ 1
hp1 : 1 < p
order_of_a : orderOf a = p - 1
this : NeZero p
⊢ p - 1 ≤ Fintype.card (ZMod p)ˣ

Next tactic:
have hp' : p - 2 + 1 = p - 1 := tsub_add_eq_add_tsub hp1
/-- If `a^(p-1) = 1 mod p`, but `a^((p-1)/q) ≠ 1 mod p` for all prime factors `q` of `p-1`, then `p`
is prime. This is true because `a` has order `p-1` in the multiplicative group mod `p`, so this
group must itself have order `p-1`, which only happens when `p` is prime.
-/
theorem lucas_primality (p : ℕ) (a : ZMod p) (ha : a ^ (p - 1) = 1)
    (hd : ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1) : p.Prime := by
  have h0 : p ≠ 0 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have h1 : p ≠ 1 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have hp1 : 1 < p := lt_of_le_of_ne h0.bot_lt h1.symm
  have order_of_a : orderOf a = p - 1 := by
    apply orderOf_eq_of_pow_and_pow_div_prime _ ha hd
    exact tsub_pos_of_lt hp1
  haveI : NeZero p := ⟨h0⟩
  rw [Nat.prime_iff_card_units]
  -- Prove cardinality of `Units` of `ZMod p` is both `≤ p-1` and `≥ p-1`
  refine' le_antisymm (Nat.card_units_zmod_lt_sub_one hp1) _
  have hp' : p - 2 + 1 = p - 1 := tsub_add_eq_add_tsub hp1
  

Proof state:
p : ℕ
a : ZMod p
ha : a ^ (p - 1) = 1
hd : ∀ (q : ℕ), Nat.Prime q → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1
h0 : p ≠ 0
h1 : p ≠ 1
hp1 : 1 < p
order_of_a : orderOf a = p - 1
this : NeZero p
hp' : p - 2 + 1 = p - 1
⊢ p - 1 ≤ Fintype.card (ZMod p)ˣ

Next tactic:
let a' : (ZMod p)ˣ := Units.mkOfMulEqOne a (a ^ (p - 2)) (by rw [← pow_succ, hp', ha])
/-- If `a^(p-1) = 1 mod p`, but `a^((p-1)/q) ≠ 1 mod p` for all prime factors `q` of `p-1`, then `p`
is prime. This is true because `a` has order `p-1` in the multiplicative group mod `p`, so this
group must itself have order `p-1`, which only happens when `p` is prime.
-/
theorem lucas_primality (p : ℕ) (a : ZMod p) (ha : a ^ (p - 1) = 1)
    (hd : ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1) : p.Prime := by
  have h0 : p ≠ 0 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have h1 : p ≠ 1 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have hp1 : 1 < p := lt_of_le_of_ne h0.bot_lt h1.symm
  have order_of_a : orderOf a = p - 1 := by
    apply orderOf_eq_of_pow_and_pow_div_prime _ ha hd
    exact tsub_pos_of_lt hp1
  haveI : NeZero p := ⟨h0⟩
  rw [Nat.prime_iff_card_units]
  -- Prove cardinality of `Units` of `ZMod p` is both `≤ p-1` and `≥ p-1`
  refine' le_antisymm (Nat.card_units_zmod_lt_sub_one hp1) _
  have hp' : p - 2 + 1 = p - 1 := tsub_add_eq_add_tsub hp1
  let a' : (ZMod p)ˣ := Units.mkOfMulEqOne a (a ^ (p - 2)) (by 

Proof state:
p : ℕ
a : ZMod p
ha : a ^ (p - 1) = 1
hd : ∀ (q : ℕ), Nat.Prime q → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1
h0 : p ≠ 0
h1 : p ≠ 1
hp1 : 1 < p
order_of_a : orderOf a = p - 1
this : NeZero p
hp' : p - 2 + 1 = p - 1
⊢ a * a ^ (p - 2) = 1

Next tactic:
rw [← pow_succ, hp', ha]
/-- If `a^(p-1) = 1 mod p`, but `a^((p-1)/q) ≠ 1 mod p` for all prime factors `q` of `p-1`, then `p`
is prime. This is true because `a` has order `p-1` in the multiplicative group mod `p`, so this
group must itself have order `p-1`, which only happens when `p` is prime.
-/
theorem lucas_primality (p : ℕ) (a : ZMod p) (ha : a ^ (p - 1) = 1)
    (hd : ∀ q : ℕ, q.Prime → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1) : p.Prime := by
  have h0 : p ≠ 0 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have h1 : p ≠ 1 := by
    rintro ⟨⟩
    exact hd 2 Nat.prime_two (dvd_zero _) (pow_zero _)
  have hp1 : 1 < p := lt_of_le_of_ne h0.bot_lt h1.symm
  have order_of_a : orderOf a = p - 1 := by
    apply orderOf_eq_of_pow_and_pow_div_prime _ ha hd
    exact tsub_pos_of_lt hp1
  haveI : NeZero p := ⟨h0⟩
  rw [Nat.prime_iff_card_units]
  -- Prove cardinality of `Units` of `ZMod p` is both `≤ p-1` and `≥ p-1`
  refine' le_antisymm (Nat.card_units_zmod_lt_sub_one hp1) _
  have hp' : p - 2 + 1 = p - 1 := tsub_add_eq_add_tsub hp1
  let a' : (ZMod p)ˣ := Units.mkOfMulEqOne a (a ^ (p - 2)) (by rw [← pow_succ, hp', ha])
  

Proof state:
p : ℕ
a : ZMod p
ha : a ^ (p - 1) = 1
hd : ∀ (q : ℕ), Nat.Prime q → q ∣ p - 1 → a ^ ((p - 1) / q) ≠ 1
h0 : p ≠ 0
h1 : p ≠ 1
hp1 : 1 < p
order_of_a : orderOf a = p - 1
this : NeZero p
hp' : p - 2 + 1 = p - 1
a' : (ZMod p)ˣ := Units.mkOfMulEqOne a (a ^ (p - 2)) (_ : a * a ^ (p - 2) = 1)
⊢ p - 1 ≤ Fintype.card (ZMod p)ˣ

Next tactic:
calc
    p - 1 = orderOf a := order_of_a.symm
    _ = orderOf a' := (orderOf_injective (Units.coeHom (ZMod p)) Units.ext a')
    _ ≤ Fintype.card (ZMod p)ˣ := orderOf_le_card_univ
@[to_additive (attr := simp)]
theorem OrderIso.mulRight_symm (a : α) : (OrderIso.mulRight a).symm = OrderIso.mulRight a⁻¹ := by
  

Proof state:
α : Type u
inst✝² : Group α
inst✝¹ : LE α
inst✝ : CovariantClass α α (swap fun x x_1 => x * x_1) fun x x_1 => x ≤ x_1
a✝ b c d a : α
⊢ symm (mulRight a) = mulRight a⁻¹

Next tactic:
ext x
@[to_additive (attr := simp)]
theorem OrderIso.mulRight_symm (a : α) : (OrderIso.mulRight a).symm = OrderIso.mulRight a⁻¹ := by
  ext x
  

Proof state:
case h.h
α : Type u
inst✝² : Group α
inst✝¹ : LE α
inst✝ : CovariantClass α α (swap fun x x_1 => x * x_1) fun x x_1 => x ≤ x_1
a✝ b c d a x : α
⊢ (symm (mulRight a)) x = (mulRight a⁻¹) x

Next tactic:
rfl
@[to_additive (attr := simp)]
theorem OrderIso.mulLeft_symm (a : α) : (OrderIso.mulLeft a).symm = OrderIso.mulLeft a⁻¹ := by
  

Proof state:
α : Type u
inst✝² : Group α
inst✝¹ : LE α
inst✝ : CovariantClass α α (fun x x_1 => x * x_1) fun x x_1 => x ≤ x_1
a : α
⊢ symm (mulLeft a) = mulLeft a⁻¹

Next tactic:
ext x
@[to_additive (attr := simp)]
theorem OrderIso.mulLeft_symm (a : α) : (OrderIso.mulLeft a).symm = OrderIso.mulLeft a⁻¹ := by
  ext x
  

Proof state:
case h.h
α : Type u
inst✝² : Group α
inst✝¹ : LE α
inst✝ : CovariantClass α α (fun x x_1 => x * x_1) fun x x_1 => x ≤ x_1
a x : α
⊢ (symm (mulLeft a)) x = (mulLeft a⁻¹) x

Next tactic:
rfl
@[simp]
theorem support_pure : (pure a).support = {a} :=
  Set.ext fun a' => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a a'✝ a' : α
⊢ a' ∈ support (pure a) ↔ a' ∈ {a}

Next tactic:
simp [mem_support_iff]
theorem mem_support_pure_iff : a' ∈ (pure a).support ↔ a' = a := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
⊢ a' ∈ support (pure a) ↔ a' = a

Next tactic:
simp
@[simp]
theorem toOuterMeasure_pure_apply : (pure a).toOuterMeasure s = if a ∈ s then 1 else 0 := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s : Set α
⊢ ↑(toOuterMeasure (pure a)) s = if a ∈ s then 1 else 0

Next tactic:
refine' (toOuterMeasure_apply (pure a) s).trans _
@[simp]
theorem toOuterMeasure_pure_apply : (pure a).toOuterMeasure s = if a ∈ s then 1 else 0 := by
  refine' (toOuterMeasure_apply (pure a) s).trans _
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s : Set α
⊢ ∑' (x : α), Set.indicator s (⇑(pure a)) x = if a ∈ s then 1 else 0

Next tactic:
split_ifs with ha
@[simp]
theorem toOuterMeasure_pure_apply : (pure a).toOuterMeasure s = if a ∈ s then 1 else 0 := by
  refine' (toOuterMeasure_apply (pure a) s).trans _
  split_ifs with ha
  · 

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s : Set α
ha : a ∈ s
⊢ ∑' (x : α), Set.indicator s (⇑(pure a)) x = 1

Next tactic:
refine' (tsum_congr fun b => _).trans (tsum_ite_eq a 1)
@[simp]
theorem toOuterMeasure_pure_apply : (pure a).toOuterMeasure s = if a ∈ s then 1 else 0 := by
  refine' (toOuterMeasure_apply (pure a) s).trans _
  split_ifs with ha
  · refine' (tsum_congr fun b => _).trans (tsum_ite_eq a 1)
    

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s : Set α
ha : a ∈ s
b : α
⊢ Set.indicator s (⇑(pure a)) b = if b = a then 1 else 0

Next tactic:
exact ite_eq_left_iff.2 fun hb => symm (ite_eq_right_iff.2 fun h => (hb <| h.symm ▸ ha).elim)
@[simp]
theorem toOuterMeasure_pure_apply : (pure a).toOuterMeasure s = if a ∈ s then 1 else 0 := by
  refine' (toOuterMeasure_apply (pure a) s).trans _
  split_ifs with ha
  · refine' (tsum_congr fun b => _).trans (tsum_ite_eq a 1)
    exact ite_eq_left_iff.2 fun hb => symm (ite_eq_right_iff.2 fun h => (hb <| h.symm ▸ ha).elim)
  · 

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s : Set α
ha : a ∉ s
⊢ ∑' (x : α), Set.indicator s (⇑(pure a)) x = 0

Next tactic:
refine' (tsum_congr fun b => _).trans tsum_zero
@[simp]
theorem toOuterMeasure_pure_apply : (pure a).toOuterMeasure s = if a ∈ s then 1 else 0 := by
  refine' (toOuterMeasure_apply (pure a) s).trans _
  split_ifs with ha
  · refine' (tsum_congr fun b => _).trans (tsum_ite_eq a 1)
    exact ite_eq_left_iff.2 fun hb => symm (ite_eq_right_iff.2 fun h => (hb <| h.symm ▸ ha).elim)
  · refine' (tsum_congr fun b => _).trans tsum_zero
    

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s : Set α
ha : a ∉ s
b : α
⊢ Set.indicator s (⇑(pure a)) b = 0

Next tactic:
exact ite_eq_right_iff.2 fun hb => ite_eq_right_iff.2 fun h => (ha <| h ▸ hb).elim
theorem toMeasure_pure : (pure a).toMeasure = Measure.dirac a :=
  Measure.ext fun s hs => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s✝ : Set α
inst✝ : MeasurableSpace α
s : Set α
hs : MeasurableSet s
⊢ ↑↑(toMeasure (pure a)) s = ↑↑(Measure.dirac a) s

Next tactic:
rw [toMeasure_pure_apply a s hs, Measure.dirac_apply' a hs]
theorem toMeasure_pure : (pure a).toMeasure = Measure.dirac a :=
  Measure.ext fun s hs => by rw [toMeasure_pure_apply a s hs, Measure.dirac_apply' a hs]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s✝ : Set α
inst✝ : MeasurableSpace α
s : Set α
hs : MeasurableSet s
⊢ (if a ∈ s then 1 else 0) = Set.indicator s 1 a

Next tactic:
rfl
@[simp]
theorem toPMF_dirac [Countable α] [h : MeasurableSingletonClass α] :
    (Measure.dirac a).toPMF = pure a := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a a' : α
s : Set α
inst✝¹ : MeasurableSpace α
inst✝ : Countable α
h : MeasurableSingletonClass α
⊢ Measure.toPMF (Measure.dirac a) = pure a

Next tactic:
rw [toPMF_eq_iff_toMeasure_eq, toMeasure_pure]
/-- The monadic bind operation for `PMF`. -/
def bind (p : PMF α) (f : α → PMF β) : PMF β :=
  ⟨fun b => ∑' a, p a * f a b,
    ENNReal.summable.hasSum_iff.2
      (ENNReal.tsum_comm.trans <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
⊢ ∑' (b : α) (a : β), p b * (f b) a = 1

Next tactic:
simp only [ENNReal.tsum_mul_left, tsum_coe, mul_one]
@[simp]
theorem support_bind : (p.bind f).support = ⋃ a ∈ p.support, (f a).support :=
  Set.ext fun b => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
b : β
⊢ b ∈ support (bind p f) ↔ b ∈ ⋃ a ∈ support p, support (f a)

Next tactic:
simp [mem_support_iff, ENNReal.tsum_eq_zero, not_or]
theorem mem_support_bind_iff (b : β) :
    b ∈ (p.bind f).support ↔ ∃ a ∈ p.support, b ∈ (f a).support := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
b : β
⊢ b ∈ support (bind p f) ↔ ∃ a ∈ support p, b ∈ support (f a)

Next tactic:
simp only [support_bind, Set.mem_iUnion, Set.mem_setOf_eq, exists_prop]
@[simp]
theorem pure_bind (a : α) (f : α → PMF β) : (pure a).bind f = f a := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f✝ : α → PMF β
g : β → PMF γ
a : α
f : α → PMF β
⊢ bind (pure a) f = f a

Next tactic:
have : ∀ b a', ite (a' = a) (f a' b) 0 = ite (a' = a) (f a b) 0 := fun b a' => by
    split_ifs with h <;> simp [h]
@[simp]
theorem pure_bind (a : α) (f : α → PMF β) : (pure a).bind f = f a := by
  have : ∀ b a', ite (a' = a) (f a' b) 0 = ite (a' = a) (f a b) 0 := fun b a' => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f✝ : α → PMF β
g : β → PMF γ
a : α
f : α → PMF β
b : β
a' : α
⊢ (if a' = a then (f a') b else 0) = if a' = a then (f a) b else 0

Next tactic:
split_ifs with h
@[simp]
theorem pure_bind (a : α) (f : α → PMF β) : (pure a).bind f = f a := by
  have : ∀ b a', ite (a' = a) (f a' b) 0 = ite (a' = a) (f a b) 0 := fun b a' => by
    split_ifs with h <;> 

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f✝ : α → PMF β
g : β → PMF γ
a : α
f : α → PMF β
b : β
a' : α
h : a' = a
⊢ (f a') b = (f a) b

Next tactic:
simp [h]
@[simp]
theorem pure_bind (a : α) (f : α → PMF β) : (pure a).bind f = f a := by
  have : ∀ b a', ite (a' = a) (f a' b) 0 = ite (a' = a) (f a b) 0 := fun b a' => by
    split_ifs with h <;> 

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f✝ : α → PMF β
g : β → PMF γ
a : α
f : α → PMF β
b : β
a' : α
h : ¬a' = a
⊢ 0 = 0

Next tactic:
simp [h]
@[simp]
theorem pure_bind (a : α) (f : α → PMF β) : (pure a).bind f = f a := by
  have : ∀ b a', ite (a' = a) (f a' b) 0 = ite (a' = a) (f a b) 0 := fun b a' => by
    split_ifs with h <;> simp [h]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f✝ : α → PMF β
g : β → PMF γ
a : α
f : α → PMF β
this : ∀ (b : β) (a' : α), (if a' = a then (f a') b else 0) = if a' = a then (f a) b else 0
⊢ bind (pure a) f = f a

Next tactic:
ext b
@[simp]
theorem pure_bind (a : α) (f : α → PMF β) : (pure a).bind f = f a := by
  have : ∀ b a', ite (a' = a) (f a' b) 0 = ite (a' = a) (f a b) 0 := fun b a' => by
    split_ifs with h <;> simp [h]
  ext b
  

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f✝ : α → PMF β
g : β → PMF γ
a : α
f : α → PMF β
this : ∀ (b : β) (a' : α), (if a' = a then (f a') b else 0) = if a' = a then (f a) b else 0
b : β
⊢ (bind (pure a) f) b = (f a) b

Next tactic:
simp [this]
@[simp]
theorem bind_pure : p.bind pure = p :=
  PMF.ext fun x => (bind_apply _ _ _).trans (_root_.trans
    (tsum_eq_single x fun y hy => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
x y : α
hy : y ≠ x
⊢ p y * (pure y) x = 0

Next tactic:
rw [pure_apply_of_ne _ _ hy.symm, mul_zero]
@[simp]
theorem bind_pure : p.bind pure = p :=
  PMF.ext fun x => (bind_apply _ _ _).trans (_root_.trans
    (tsum_eq_single x fun y hy => by rw [pure_apply_of_ne _ _ hy.symm, mul_zero]) <|
    by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
x : α
⊢ p x * (pure x) x = p x

Next tactic:
rw [pure_apply_self, mul_one]
@[simp]
theorem bind_const (p : PMF α) (q : PMF β) : (p.bind fun _ => q) = q :=
  PMF.ext fun x => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p✝ : PMF α
f : α → PMF β
g : β → PMF γ
p : PMF α
q : PMF β
x : β
⊢ (bind p fun x => q) x = q x

Next tactic:
rw [bind_apply, ENNReal.tsum_mul_right, tsum_coe, one_mul]
@[simp]
theorem bind_bind : (p.bind f).bind g = p.bind fun a => (f a).bind g :=
  PMF.ext fun b => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
b : γ
⊢ (bind (bind p f) g) b = (bind p fun a => bind (f a) g) b

Next tactic:
simpa only [ENNReal.coe_eq_coe.symm, bind_apply, ENNReal.tsum_mul_left.symm,
      ENNReal.tsum_mul_right.symm, mul_assoc, mul_left_comm, mul_comm] using ENNReal.tsum_comm
theorem bind_comm (p : PMF α) (q : PMF β) (f : α → β → PMF γ) :
    (p.bind fun a => q.bind (f a)) = q.bind fun b => p.bind fun a => f a b :=
  PMF.ext fun b => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p✝ : PMF α
f✝ : α → PMF β
g : β → PMF γ
p : PMF α
q : PMF β
f : α → β → PMF γ
b : γ
⊢ (bind p fun a => bind q (f a)) b = (bind q fun b => bind p fun a => f a b) b

Next tactic:
simpa only [ENNReal.coe_eq_coe.symm, bind_apply, ENNReal.tsum_mul_left.symm,
      ENNReal.tsum_mul_right.symm, mul_assoc, mul_left_comm, mul_comm] using ENNReal.tsum_comm
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
⊢ ↑(toOuterMeasure (bind p f)) s = ∑' (b : β), if b ∈ s then ∑' (a : α), p a * (f a) b else 0

Next tactic:
simp [toOuterMeasure_apply, Set.indicator_apply]
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      simp [toOuterMeasure_apply, Set.indicator_apply]
    _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := (tsum_congr fun b => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
b : β
⊢ (if b ∈ s then ∑' (a : α), p a * (f a) b else 0) = ∑' (a : α), p a * if b ∈ s then (f a) b else 0

Next tactic:
split_ifs
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      simp [toOuterMeasure_apply, Set.indicator_apply]
    _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := (tsum_congr fun b => by split_ifs <;> 

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
b : β
h✝ : b ∈ s
⊢ ∑' (a : α), p a * (f a) b = ∑' (a : α), p a * (f a) b

Next tactic:
simp
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      simp [toOuterMeasure_apply, Set.indicator_apply]
    _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := (tsum_congr fun b => by split_ifs <;> 

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
b : β
h✝ : b ∉ s
⊢ 0 = ∑' (a : α), p a * 0

Next tactic:
simp
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      simp [toOuterMeasure_apply, Set.indicator_apply]
    _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := (tsum_congr fun b => by split_ifs <;> simp)
    _ = ∑' (a) (b), p a * if b ∈ s then f a b else 0 :=
      (tsum_comm' ENNReal.summable (fun _ => ENNReal.summable) fun _ => ENNReal.summable)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 := (tsum_congr fun a => ENNReal.tsum_mul_left)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 :=
      (tsum_congr fun a => (congr_arg fun x => p a * x) <| tsum_congr fun b => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
a : α
b : β
⊢ (if b ∈ s then (f a) b else 0) = if b ∈ s then (f a) b else 0

Next tactic:
split_ifs
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      simp [toOuterMeasure_apply, Set.indicator_apply]
    _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := (tsum_congr fun b => by split_ifs <;> simp)
    _ = ∑' (a) (b), p a * if b ∈ s then f a b else 0 :=
      (tsum_comm' ENNReal.summable (fun _ => ENNReal.summable) fun _ => ENNReal.summable)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 := (tsum_congr fun a => ENNReal.tsum_mul_left)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 :=
      (tsum_congr fun a => (congr_arg fun x => p a * x) <| tsum_congr fun b => by split_ifs <;> 

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
a : α
b : β
h✝ : b ∈ s
⊢ (f a) b = (f a) b

Next tactic:
rfl
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      simp [toOuterMeasure_apply, Set.indicator_apply]
    _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := (tsum_congr fun b => by split_ifs <;> simp)
    _ = ∑' (a) (b), p a * if b ∈ s then f a b else 0 :=
      (tsum_comm' ENNReal.summable (fun _ => ENNReal.summable) fun _ => ENNReal.summable)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 := (tsum_congr fun a => ENNReal.tsum_mul_left)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 :=
      (tsum_congr fun a => (congr_arg fun x => p a * x) <| tsum_congr fun b => by split_ifs <;> 

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
a : α
b : β
h✝ : b ∉ s
⊢ 0 = 0

Next tactic:
rfl
@[simp]
theorem toOuterMeasure_bind_apply :
    (p.bind f).toOuterMeasure s = ∑' a, p a * (f a).toOuterMeasure s :=
  calc
    (p.bind f).toOuterMeasure s = ∑' b, if b ∈ s then ∑' a, p a * f a b else 0 := by
      simp [toOuterMeasure_apply, Set.indicator_apply]
    _ = ∑' (b) (a), p a * if b ∈ s then f a b else 0 := (tsum_congr fun b => by split_ifs <;> simp)
    _ = ∑' (a) (b), p a * if b ∈ s then f a b else 0 :=
      (tsum_comm' ENNReal.summable (fun _ => ENNReal.summable) fun _ => ENNReal.summable)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 := (tsum_congr fun a => ENNReal.tsum_mul_left)
    _ = ∑' a, p a * ∑' b, if b ∈ s then f a b else 0 :=
      (tsum_congr fun a => (congr_arg fun x => p a * x) <| tsum_congr fun b => by split_ifs <;> rfl)
    _ = ∑' a, p a * (f a).toOuterMeasure s :=
      tsum_congr fun a => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : PMF α
f : α → PMF β
g : β → PMF γ
s : Set β
a : α
⊢ (p a * ∑' (b : β), if b ∈ s then (f a) b else 0) = p a * ↑(toOuterMeasure (f a)) s

Next tactic:
simp only [toOuterMeasure_apply, Set.indicator_apply]