l3lab/ntp-mathlib huggingface dataset:
/-- It is equivalent to compute the product of a function over `Fin n` or `Finset.range n`. -/
@[to_additive "It is equivalent to sum a function over `fin n` or `finset.range n`."]
theorem Fin.prod_univ_eq_prod_range [CommMonoid α] (f : ℕ → α) (n : ℕ) :
    ∏ i : Fin n, f i = ∏ i in range n, f i :=
  calc
    ∏ i : Fin n, f i = ∏ i : { x // x ∈ range n }, f i :=
      (Fin.equivSubtype.trans (Equiv.subtypeEquivRight (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : CommMonoid α
f : ℕ → α
n : ℕ
⊢ ∀ (x : ℕ), x < n ↔ x ∈ range n

Next tactic:
simp
/-- It is equivalent to compute the product of a function over `Fin n` or `Finset.range n`. -/
@[to_additive "It is equivalent to sum a function over `fin n` or `finset.range n`."]
theorem Fin.prod_univ_eq_prod_range [CommMonoid α] (f : ℕ → α) (n : ℕ) :
    ∏ i : Fin n, f i = ∏ i in range n, f i :=
  calc
    ∏ i : Fin n, f i = ∏ i : { x // x ∈ range n }, f i :=
      (Fin.equivSubtype.trans (Equiv.subtypeEquivRight (by simp))).prod_comp' _ _ (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : CommMonoid α
f : ℕ → α
n : ℕ
⊢ ∀ (i : Fin n), f ↑i = f ↑((equivSubtype.trans (Equiv.subtypeEquivRight (_ : ∀ (a : ℕ), a < n ↔ a ∈ range n))) i)

Next tactic:
simp
/-- It is equivalent to compute the product of a function over `Fin n` or `Finset.range n`. -/
@[to_additive "It is equivalent to sum a function over `fin n` or `finset.range n`."]
theorem Fin.prod_univ_eq_prod_range [CommMonoid α] (f : ℕ → α) (n : ℕ) :
    ∏ i : Fin n, f i = ∏ i in range n, f i :=
  calc
    ∏ i : Fin n, f i = ∏ i : { x // x ∈ range n }, f i :=
      (Fin.equivSubtype.trans (Equiv.subtypeEquivRight (by simp))).prod_comp' _ _ (by simp)
    _ = ∏ i in range n, f i := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : CommMonoid α
f : ℕ → α
n : ℕ
⊢ ∏ i : { x // x ∈ range n }, f ↑i = ∏ i in range n, f i

Next tactic:
rw [← attach_eq_univ, prod_attach]
@[to_additive]
theorem Finset.prod_fin_eq_prod_range [CommMonoid β] {n : ℕ} (c : Fin n → β) :
    ∏ i, c i = ∏ i in Finset.range n, if h : i < n then c ⟨i, h⟩ else 1 := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : CommMonoid β
n : ℕ
c : Fin n → β
⊢ ∏ i : Fin n, c i = ∏ i in range n, if h : i < n then c { val := i, isLt := h } else 1

Next tactic:
rw [← Fin.prod_univ_eq_prod_range, Finset.prod_congr rfl]
@[to_additive]
theorem Finset.prod_fin_eq_prod_range [CommMonoid β] {n : ℕ} (c : Fin n → β) :
    ∏ i, c i = ∏ i in Finset.range n, if h : i < n then c ⟨i, h⟩ else 1 := by
  rw [← Fin.prod_univ_eq_prod_range, Finset.prod_congr rfl]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : CommMonoid β
n : ℕ
c : Fin n → β
⊢ ∀ x ∈ univ, c x = if h : ↑x < n then c { val := ↑x, isLt := h } else 1

Next tactic:
rintro ⟨i, hi⟩ _
@[to_additive]
theorem Finset.prod_fin_eq_prod_range [CommMonoid β] {n : ℕ} (c : Fin n → β) :
    ∏ i, c i = ∏ i in Finset.range n, if h : i < n then c ⟨i, h⟩ else 1 := by
  rw [← Fin.prod_univ_eq_prod_range, Finset.prod_congr rfl]
  rintro ⟨i, hi⟩ _
  

Proof state:
case mk
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : CommMonoid β
n : ℕ
c : Fin n → β
i : ℕ
hi : i < n
a✝ : { val := i, isLt := hi } ∈ univ
⊢ c { val := i, isLt := hi } =
    if h : ↑{ val := i, isLt := hi } < n then c { val := ↑{ val := i, isLt := hi }, isLt := h } else 1

Next tactic:
simp only [hi, dif_pos]
@[to_additive]
theorem Finset.prod_toFinset_eq_subtype {M : Type*} [CommMonoid M] [Fintype α] (p : α → Prop)
    [DecidablePred p] (f : α → M) : ∏ a in { x | p x }.toFinset, f a = ∏ a : Subtype p, f a := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
M : Type u_4
inst✝² : CommMonoid M
inst✝¹ : Fintype α
p : α → Prop
inst✝ : DecidablePred p
f : α → M
⊢ ∏ a in Set.toFinset {x | p x}, f a = ∏ a : Subtype p, f ↑a

Next tactic:
rw [← Finset.prod_subtype]
@[to_additive]
theorem Finset.prod_toFinset_eq_subtype {M : Type*} [CommMonoid M] [Fintype α] (p : α → Prop)
    [DecidablePred p] (f : α → M) : ∏ a in { x | p x }.toFinset, f a = ∏ a : Subtype p, f a := by
  rw [← Finset.prod_subtype]
  

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
M : Type u_4
inst✝² : CommMonoid M
inst✝¹ : Fintype α
p : α → Prop
inst✝ : DecidablePred p
f : α → M
⊢ ∀ (x : α), x ∈ Set.toFinset {x | p x} ↔ p x

Next tactic:
simp_rw [Set.mem_toFinset]
@[to_additive]
theorem Finset.prod_toFinset_eq_subtype {M : Type*} [CommMonoid M] [Fintype α] (p : α → Prop)
    [DecidablePred p] (f : α → M) : ∏ a in { x | p x }.toFinset, f a = ∏ a : Subtype p, f a := by
  rw [← Finset.prod_subtype]
  simp_rw [Set.mem_toFinset]; 

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
M : Type u_4
inst✝² : CommMonoid M
inst✝¹ : Fintype α
p : α → Prop
inst✝ : DecidablePred p
f : α → M
⊢ ∀ (x : α), x ∈ {x | p x} ↔ p x

Next tactic:
intro
@[to_additive]
theorem Finset.prod_toFinset_eq_subtype {M : Type*} [CommMonoid M] [Fintype α] (p : α → Prop)
    [DecidablePred p] (f : α → M) : ∏ a in { x | p x }.toFinset, f a = ∏ a : Subtype p, f a := by
  rw [← Finset.prod_subtype]
  simp_rw [Set.mem_toFinset]; intro; 

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
M : Type u_4
inst✝² : CommMonoid M
inst✝¹ : Fintype α
p : α → Prop
inst✝ : DecidablePred p
f : α → M
x✝ : α
⊢ x✝ ∈ {x | p x} ↔ p x✝

Next tactic:
rfl
@[to_additive]
theorem Fintype.prod_fiberwise [Fintype α] [DecidableEq β] [Fintype β] [CommMonoid γ] (f : α → β)
    (g : α → γ) : (∏ b : β, ∏ a : { a // f a = b }, g (a : α)) = ∏ a, g a := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝³ : Fintype α
inst✝² : DecidableEq β
inst✝¹ : Fintype β
inst✝ : CommMonoid γ
f : α → β
g : α → γ
⊢ ∏ b : β, ∏ a : { a // f a = b }, g ↑a = ∏ a : α, g a

Next tactic:
rw [← (Equiv.sigmaFiberEquiv f).prod_comp, ← univ_sigma_univ, prod_sigma]
@[to_additive]
theorem Fintype.prod_fiberwise [Fintype α] [DecidableEq β] [Fintype β] [CommMonoid γ] (f : α → β)
    (g : α → γ) : (∏ b : β, ∏ a : { a // f a = b }, g (a : α)) = ∏ a, g a := by
  rw [← (Equiv.sigmaFiberEquiv f).prod_comp, ← univ_sigma_univ, prod_sigma]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝³ : Fintype α
inst✝² : DecidableEq β
inst✝¹ : Fintype β
inst✝ : CommMonoid γ
f : α → β
g : α → γ
⊢ ∏ b : β, ∏ a : { a // f a = b }, g ↑a =
    ∏ a : β, ∏ s : { x // f x = a }, g ((Equiv.sigmaFiberEquiv f) { fst := a, snd := s })

Next tactic:
rfl
nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β]
    (f : ∀ (a : α) (_ha : p a), β) (g : ∀ (a : α) (_ha : ¬p a), β) :
    (∏ a, dite (p a) (f a) (g a)) =
    (∏ a : { a // p a }, f a a.2) * ∏ a : { a // ¬p a }, g a a.2 := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : Fintype α
p : α → Prop
inst✝¹ : DecidablePred p
inst✝ : CommMonoid β
f : (a : α) → p a → β
g : (a : α) → ¬p a → β
⊢ ∏ a : α, dite (p a) (f a) (g a) = (∏ a : { a // p a }, f ↑a (_ : p ↑a)) * ∏ a : { a // ¬p a }, g ↑a (_ : ¬p ↑a)

Next tactic:
simp only [prod_dite, attach_eq_univ]
nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β]
    (f : ∀ (a : α) (_ha : p a), β) (g : ∀ (a : α) (_ha : ¬p a), β) :
    (∏ a, dite (p a) (f a) (g a)) =
    (∏ a : { a // p a }, f a a.2) * ∏ a : { a // ¬p a }, g a a.2 := by
  simp only [prod_dite, attach_eq_univ]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : Fintype α
p : α → Prop
inst✝¹ : DecidablePred p
inst✝ : CommMonoid β
f : (a : α) → p a → β
g : (a : α) → ¬p a → β
⊢ (∏ x : { x // x ∈ filter (fun x => p x) univ }, f ↑x (_ : p ↑x)) *
      ∏ x : { x // x ∈ filter (fun x => ¬p x) univ }, g ↑x (_ : ¬p ↑x) =
    (∏ a : { a // p a }, f ↑a (_ : p ↑a)) * ∏ a : { a // ¬p a }, g ↑a (_ : ¬p ↑a)

Next tactic:
congr 1
nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β]
    (f : ∀ (a : α) (_ha : p a), β) (g : ∀ (a : α) (_ha : ¬p a), β) :
    (∏ a, dite (p a) (f a) (g a)) =
    (∏ a : { a // p a }, f a a.2) * ∏ a : { a // ¬p a }, g a a.2 := by
  simp only [prod_dite, attach_eq_univ]
  congr 1
  · 

Proof state:
case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : Fintype α
p : α → Prop
inst✝¹ : DecidablePred p
inst✝ : CommMonoid β
f : (a : α) → p a → β
g : (a : α) → ¬p a → β
⊢ ∏ x : { x // x ∈ filter (fun x => p x) univ }, f ↑x (_ : p ↑x) = ∏ a : { a // p a }, f ↑a (_ : p ↑a)

Next tactic:
exact (Equiv.subtypeEquivRight $ by simp).prod_comp fun x : { x // p x } => f x x.2
nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β]
    (f : ∀ (a : α) (_ha : p a), β) (g : ∀ (a : α) (_ha : ¬p a), β) :
    (∏ a, dite (p a) (f a) (g a)) =
    (∏ a : { a // p a }, f a a.2) * ∏ a : { a // ¬p a }, g a a.2 := by
  simp only [prod_dite, attach_eq_univ]
  congr 1
  · exact (Equiv.subtypeEquivRight $ by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : Fintype α
p : α → Prop
inst✝¹ : DecidablePred p
inst✝ : CommMonoid β
f : (a : α) → p a → β
g : (a : α) → ¬p a → β
⊢ ∀ (x : α), x ∈ filter (fun x => p x) univ ↔ p x

Next tactic:
simp
nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β]
    (f : ∀ (a : α) (_ha : p a), β) (g : ∀ (a : α) (_ha : ¬p a), β) :
    (∏ a, dite (p a) (f a) (g a)) =
    (∏ a : { a // p a }, f a a.2) * ∏ a : { a // ¬p a }, g a a.2 := by
  simp only [prod_dite, attach_eq_univ]
  congr 1
  · exact (Equiv.subtypeEquivRight $ by simp).prod_comp fun x : { x // p x } => f x x.2
  · 

Proof state:
case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : Fintype α
p : α → Prop
inst✝¹ : DecidablePred p
inst✝ : CommMonoid β
f : (a : α) → p a → β
g : (a : α) → ¬p a → β
⊢ ∏ x : { x // x ∈ filter (fun x => ¬p x) univ }, g ↑x (_ : ¬p ↑x) = ∏ a : { a // ¬p a }, g ↑a (_ : ¬p ↑a)

Next tactic:
exact (Equiv.subtypeEquivRight $ by simp).prod_comp fun x : { x // ¬p x } => g x x.2
nonrec theorem Fintype.prod_dite [Fintype α] {p : α → Prop} [DecidablePred p] [CommMonoid β]
    (f : ∀ (a : α) (_ha : p a), β) (g : ∀ (a : α) (_ha : ¬p a), β) :
    (∏ a, dite (p a) (f a) (g a)) =
    (∏ a : { a // p a }, f a a.2) * ∏ a : { a // ¬p a }, g a a.2 := by
  simp only [prod_dite, attach_eq_univ]
  congr 1
  · exact (Equiv.subtypeEquivRight $ by simp).prod_comp fun x : { x // p x } => f x x.2
  · exact (Equiv.subtypeEquivRight $ by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : Fintype α
p : α → Prop
inst✝¹ : DecidablePred p
inst✝ : CommMonoid β
f : (a : α) → p a → β
g : (a : α) → ¬p a → β
⊢ ∀ (x : α), x ∈ filter (fun x => ¬p x) univ ↔ ¬p x

Next tactic:
simp
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  

Proof state:
p : Prop
as ps as₁ : List Prop
⊢ as = List.reverseAux as₁ ps → implies (mk as) p ps (List.length as₁) → p

Next tactic:
induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
    induction as₁ with simp
    | cons b as₁ ih => exact fun n bs ↦ ih (n+1) _ (Nat.succ_add ..) _
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  

Proof state:
case nil
p : Prop
as as₁ : List Prop
⊢ as = List.reverseAux as₁ [] → implies (mk as) p [] (List.length as₁) → p

Next tactic:
| nil => exact fun _ ↦ id
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => 

Proof state:
case nil
p : Prop
as as₁ : List Prop
⊢ as = List.reverseAux as₁ [] → implies (mk as) p [] (List.length as₁) → p

Next tactic:
exact fun _ ↦ id
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  

Proof state:
case cons
p : Prop
as✝ : List Prop
a : Prop
as : List Prop
ih : ∀ (as₁ : List Prop), as✝ = List.reverseAux as₁ as → implies (mk as✝) p as (List.length as₁) → p
as₁ : List Prop
⊢ as✝ = List.reverseAux as₁ (a :: as) → implies (mk as✝) p (a :: as) (List.length as₁) → p

Next tactic:
| cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
    induction as₁ with simp
    | cons b as₁ ih => exact fun n bs ↦ ih (n+1) _ (Nat.succ_add ..) _
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    

Proof state:
case cons
p : Prop
as✝ : List Prop
a : Prop
as : List Prop
ih : ∀ (as₁ : List Prop), as✝ = List.reverseAux as₁ as → implies (mk as✝) p as (List.length as₁) → p
as₁ : List Prop
⊢ as✝ = List.reverseAux as₁ (a :: as) → implies (mk as✝) p (a :: as) (List.length as₁) → p

Next tactic:
refine fun e H ↦ @ih (a::as₁) e (H ?_)
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    

Proof state:
case cons
p : Prop
as✝ : List Prop
a : Prop
as : List Prop
ih : ∀ (as₁ : List Prop), as✝ = List.reverseAux as₁ as → implies (mk as✝) p as (List.length as₁) → p
as₁ : List Prop
e : as✝ = List.reverseAux as₁ (a :: as)
H : implies (mk as✝) p (a :: as) (List.length as₁)
⊢ mk as✝ (List.length as₁) ↔ a

Next tactic:
subst e
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; 

Proof state:
case cons
p a : Prop
as as₁ : List Prop
ih :
  ∀ (as₁_1 : List Prop),
    List.reverseAux as₁ (a :: as) = List.reverseAux as₁_1 as →
      implies (mk (List.reverseAux as₁ (a :: as))) p as (List.length as₁_1) → p
H : implies (mk (List.reverseAux as₁ (a :: as))) p (a :: as) (List.length as₁)
⊢ mk (List.reverseAux as₁ (a :: as)) (List.length as₁) ↔ a

Next tactic:
clear ih H
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    

Proof state:
case cons
p a : Prop
as as₁ : List Prop
⊢ mk (List.reverseAux as₁ (a :: as)) (List.length as₁) ↔ a

Next tactic:
suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
    

Proof state:
case cons
p a : Prop
as as₁ : List Prop
⊢ ∀ (n n' : ℕ), n' = List.length as₁ + n → ∀ (bs : List Prop), mk (List.reverseAux as₁ bs) n' ↔ mk bs n

Next tactic:
induction as₁ with simp
    | cons b as₁ ih => exact fun n bs ↦ ih (n+1) _ (Nat.succ_add ..) _
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
    induction as₁ with 

Proof state:
case cons.cons
p a : Prop
as : List Prop
b : Prop
as₁ : List Prop
ih : ∀ (n n' : ℕ), n' = List.length as₁ + n → ∀ (bs : List Prop), mk (List.reverseAux as₁ bs) n' ↔ mk bs n
⊢ ∀ (n n' : ℕ), n' = List.length (b :: as₁) + n → ∀ (bs : List Prop), mk (List.reverseAux (b :: as₁) bs) n' ↔ mk bs n

Next tactic:
simp
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
    induction as₁ with simp
    

Proof state:
case cons.cons
p a : Prop
as : List Prop
b : Prop
as₁ : List Prop
ih : ∀ (n n' : ℕ), n' = List.length as₁ + n → ∀ (bs : List Prop), mk (List.reverseAux as₁ bs) n' ↔ mk bs n
⊢ ∀ (n : ℕ) (bs : List Prop), mk (List.reverseAux as₁ (b :: bs)) (Nat.succ (List.length as₁) + n) ↔ mk bs n

Next tactic:
| cons b as₁ ih => exact fun n bs ↦ ih (n+1) _ (Nat.succ_add ..) _
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
    induction as₁ with simp
    | cons b as₁ ih => 

Proof state:
case cons.cons
p a : Prop
as : List Prop
b : Prop
as₁ : List Prop
ih : ∀ (n n' : ℕ), n' = List.length as₁ + n → ∀ (bs : List Prop), mk (List.reverseAux as₁ bs) n' ↔ mk bs n
⊢ ∀ (n : ℕ) (bs : List Prop), mk (List.reverseAux as₁ (b :: bs)) (Nat.succ (List.length as₁) + n) ↔ mk bs n

Next tactic:
exact fun n bs ↦ ih (n+1) _ (Nat.succ_add ..) _
/-- The fundamental relationship between `mk` and `implies`:
`(mk ps).implies p ps 0` is equivalent to `p`. -/
theorem Valuation.mk_implies {as ps} (as₁) : as = List.reverseAux as₁ ps →
    (Valuation.mk as).implies p ps as₁.length → p := by
  induction ps generalizing as₁ with
  | nil => exact fun _ ↦ id
  | cons a as ih =>
    refine fun e H ↦ @ih (a::as₁) e (H ?_)
    subst e; clear ih H
    suffices ∀ n n', n' = List.length as₁ + n →
      ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as)
    induction as₁ with 

Proof state:
case cons.nil
p a : Prop
as : List Prop
⊢ ∀ (n n' : ℕ), n' = List.length [] + n → ∀ (bs : List Prop), mk (List.reverseAux [] bs) n' ↔ mk bs n

Next tactic:
simp
/-- Negation turns AND into OR, so `¬⟦f₁ ∧ f₂⟧_v ≡ ¬⟦f₁⟧_v ∨ ¬⟦f₂⟧_v`. -/
theorem Fmla.reify_or (h₁ : Fmla.reify v f₁ a) (h₂ : Fmla.reify v f₂ b) :
    Fmla.reify v (f₁.and f₂) (a ∨ b) := by
  

Proof state:
v : Valuation
f₁ : Fmla
a : Prop
f₂ : Fmla
b : Prop
h₁ : reify v f₁ a
h₂ : reify v f₂ b
⊢ reify v (and f₁ f₂) (a ∨ b)

Next tactic:
refine ⟨fun H ↦ by_contra fun hn ↦ H ⟨fun c h ↦ by_contra fun hn' ↦ ?_⟩⟩
/-- Negation turns AND into OR, so `¬⟦f₁ ∧ f₂⟧_v ≡ ¬⟦f₁⟧_v ∨ ¬⟦f₂⟧_v`. -/
theorem Fmla.reify_or (h₁ : Fmla.reify v f₁ a) (h₂ : Fmla.reify v f₂ b) :
    Fmla.reify v (f₁.and f₂) (a ∨ b) := by
  refine ⟨fun H ↦ by_contra fun hn ↦ H ⟨fun c h ↦ by_contra fun hn' ↦ ?_⟩⟩
  

Proof state:
v : Valuation
f₁ : Fmla
a : Prop
f₂ : Fmla
b : Prop
h₁ : reify v f₁ a
h₂ : reify v f₂ b
H : ¬Valuation.satisfies_fmla v (and f₁ f₂)
hn : ¬(a ∨ b)
c : Clause
h : c ∈ and f₁ f₂
hn' : ¬Valuation.satisfies v c
⊢ False

Next tactic:
rcases List.mem_append.1 h with h | h
/-- Negation turns AND into OR, so `¬⟦f₁ ∧ f₂⟧_v ≡ ¬⟦f₁⟧_v ∨ ¬⟦f₂⟧_v`. -/
theorem Fmla.reify_or (h₁ : Fmla.reify v f₁ a) (h₂ : Fmla.reify v f₂ b) :
    Fmla.reify v (f₁.and f₂) (a ∨ b) := by
  refine ⟨fun H ↦ by_contra fun hn ↦ H ⟨fun c h ↦ by_contra fun hn' ↦ ?_⟩⟩
  rcases List.mem_append.1 h with h | h
  · 

Proof state:
case inl
v : Valuation
f₁ : Fmla
a : Prop
f₂ : Fmla
b : Prop
h₁ : reify v f₁ a
h₂ : reify v f₂ b
H : ¬Valuation.satisfies_fmla v (and f₁ f₂)
hn : ¬(a ∨ b)
c : Clause
h✝ : c ∈ and f₁ f₂
hn' : ¬Valuation.satisfies v c
h : c ∈ f₁
⊢ False

Next tactic:
exact hn $ Or.inl $ h₁.1 fun Hc ↦ hn' $ Hc.1 _ h
/-- Negation turns AND into OR, so `¬⟦f₁ ∧ f₂⟧_v ≡ ¬⟦f₁⟧_v ∨ ¬⟦f₂⟧_v`. -/
theorem Fmla.reify_or (h₁ : Fmla.reify v f₁ a) (h₂ : Fmla.reify v f₂ b) :
    Fmla.reify v (f₁.and f₂) (a ∨ b) := by
  refine ⟨fun H ↦ by_contra fun hn ↦ H ⟨fun c h ↦ by_contra fun hn' ↦ ?_⟩⟩
  rcases List.mem_append.1 h with h | h
  · exact hn $ Or.inl $ h₁.1 fun Hc ↦ hn' $ Hc.1 _ h
  · 

Proof state:
case inr
v : Valuation
f₁ : Fmla
a : Prop
f₂ : Fmla
b : Prop
h₁ : reify v f₁ a
h₂ : reify v f₂ b
H : ¬Valuation.satisfies_fmla v (and f₁ f₂)
hn : ¬(a ∨ b)
c : Clause
h✝ : c ∈ and f₁ f₂
hn' : ¬Valuation.satisfies v c
h : c ∈ f₂
⊢ False

Next tactic:
exact hn $ Or.inr $ h₂.1 fun Hc ↦ hn' $ Hc.1 _ h
@[simp]
theorem card_Icc : (Icc a b).card = b + 1 - a := by
  

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

Next tactic:
rw [← Nat.card_Icc]
@[simp]
theorem card_Icc : (Icc a b).card = b + 1 - a := by
  rw [← Nat.card_Icc]
  -- 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 (Icc a b) = card (Icc ↑a ↑b)

Next tactic:
erw [← Finset.map_subtype_embedding_Icc _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
@[simp]
theorem card_Icc : (Icc a b).card = b + 1 - a := by
  rw [← Nat.card_Icc]
  -- 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_Icc _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
  

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

Next tactic:
rw [card_map]
@[simp]
theorem card_Ico : (Ico a b).card = b - a := by
  

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

Next tactic:
rw [← Nat.card_Ico]
@[simp]
theorem card_Ico : (Ico a b).card = b - a := by
  rw [← Nat.card_Ico]
  -- 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 (Ico a b) = card (Ico ↑a ↑b)

Next tactic:
erw [← Finset.map_subtype_embedding_Ico _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
@[simp]
theorem card_Ico : (Ico a b).card = b - a := by
  rw [← Nat.card_Ico]
  -- 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_Ico _ a b (fun c x _ hx _ hc _ => hc.trans_le hx)]
  

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

Next tactic:
rw [card_map]
@[simp]
theorem card_Ioc : (Ioc a b).card = b - a := by
  

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

Next tactic:
rw [← Nat.card_Ioc]