l3lab/ntp-mathlib huggingface dataset:
instance : IsWellFounded (Products I) (·<·) := by
  have : (· < · : Products I → _ → _) = (fun l m ↦ List.Lex (·<·) l.val m.val) := by
    ext; 

Proof state:
case h.h.a
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
x✝¹ x✝ : Products I
⊢ x✝¹ < x✝ ↔ List.Lex (fun x x_1 => x < x_1) ↑x✝¹ ↑x✝

Next tactic:
exact lt_iff_lex_lt _ _
instance : IsWellFounded (Products I) (·<·) := by
  have : (· < · : Products I → _ → _) = (fun l m ↦ List.Lex (·<·) l.val m.val) := by
    ext; exact lt_iff_lex_lt _ _
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
this : (fun x x_1 => x < x_1) = fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m
⊢ IsWellFounded (Products I) fun x x_1 => x < x_1

Next tactic:
rw [this]
instance : IsWellFounded (Products I) (·<·) := by
  have : (· < · : Products I → _ → _) = (fun l m ↦ List.Lex (·<·) l.val m.val) := by
    ext; exact lt_iff_lex_lt _ _
  rw [this]
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
this : (fun x x_1 => x < x_1) = fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m
⊢ IsWellFounded (Products I) fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m

Next tactic:
dsimp [Products]
instance : IsWellFounded (Products I) (·<·) := by
  have : (· < · : Products I → _ → _) = (fun l m ↦ List.Lex (·<·) l.val m.val) := by
    ext; exact lt_iff_lex_lt _ _
  rw [this]
  dsimp [Products]
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
this : (fun x x_1 => x < x_1) = fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m
⊢ IsWellFounded { l // List.Chain' (fun x x_1 => x > x_1) l } fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m

Next tactic:
rw [(by rfl : (·>· : I → _) = flip (·<·))]
instance : IsWellFounded (Products I) (·<·) := by
  have : (· < · : Products I → _ → _) = (fun l m ↦ List.Lex (·<·) l.val m.val) := by
    ext; exact lt_iff_lex_lt _ _
  rw [this]
  dsimp [Products]
  rw [(by 

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
this : (fun x x_1 => x < x_1) = fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m
⊢ (fun x x_1 => x > x_1) = flip fun x x_1 => x < x_1

Next tactic:
rfl
instance : IsWellFounded (Products I) (·<·) := by
  have : (· < · : Products I → _ → _) = (fun l m ↦ List.Lex (·<·) l.val m.val) := by
    ext; exact lt_iff_lex_lt _ _
  rw [this]
  dsimp [Products]
  rw [(by rfl : (·>· : I → _) = flip (·<·))]
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
this : (fun x x_1 => x < x_1) = fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m
⊢ IsWellFounded { l // List.Chain' (flip fun x x_1 => x < x_1) l } fun l m => List.Lex (fun x x_1 => x < x_1) ↑l ↑m

Next tactic:
infer_instance
theorem injective : Function.Injective (eval C) := by
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
⊢ Function.Injective (eval C)

Next tactic:
intro ⟨a, ha⟩ ⟨b, hb⟩ h
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : eval C { val := a, property := ha } = eval C { val := b, property := hb }
⊢ { val := a, property := ha } = { val := b, property := hb }

Next tactic:
dsimp [eval] at h
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
⊢ { val := a, property := ha } = { val := b, property := hb }

Next tactic:
rcases lt_trichotomy a b with (h'|rfl|h')
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · 

Proof state:
case inl
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : a < b
⊢ { val := a, property := ha } = { val := b, property := hb }

Next tactic:
exfalso
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; 

Proof state:
case inl.h
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : a < b
⊢ False

Next tactic:
apply hb
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; apply hb; 

Proof state:
case inl.h
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : a < b
⊢ Products.eval C b ∈ Submodule.span ℤ (Products.eval C '' {m | m < b})

Next tactic:
rw [← h]
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; apply hb; rw [← h]
    

Proof state:
case inl.h
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : a < b
⊢ Products.eval C a ∈ Submodule.span ℤ (Products.eval C '' {m | m < b})

Next tactic:
exact Submodule.subset_span ⟨a, h', rfl⟩
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; apply hb; rw [← h]
    exact Submodule.subset_span ⟨a, h', rfl⟩
  · 

Proof state:
case inr.inl
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha hb : Products.isGood C a
h : Products.eval C a = Products.eval C a
⊢ { val := a, property := ha } = { val := a, property := hb }

Next tactic:
rfl
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; apply hb; rw [← h]
    exact Submodule.subset_span ⟨a, h', rfl⟩
  · rfl
  · 

Proof state:
case inr.inr
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : b < a
⊢ { val := a, property := ha } = { val := b, property := hb }

Next tactic:
exfalso
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; apply hb; rw [← h]
    exact Submodule.subset_span ⟨a, h', rfl⟩
  · rfl
  · exfalso; 

Proof state:
case inr.inr.h
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : b < a
⊢ False

Next tactic:
apply ha
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; apply hb; rw [← h]
    exact Submodule.subset_span ⟨a, h', rfl⟩
  · rfl
  · exfalso; apply ha; 

Proof state:
case inr.inr.h
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : b < a
⊢ Products.eval C a ∈ Submodule.span ℤ (Products.eval C '' {m | m < a})

Next tactic:
rw [h]
theorem injective : Function.Injective (eval C) := by
  intro ⟨a, ha⟩ ⟨b, hb⟩ h
  dsimp [eval] at h
  rcases lt_trichotomy a b with (h'|rfl|h')
  · exfalso; apply hb; rw [← h]
    exact Submodule.subset_span ⟨a, h', rfl⟩
  · rfl
  · exfalso; apply ha; rw [h]
    

Proof state:
case inr.inr.h
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
a : Products I
ha : Products.isGood C a
b : Products I
hb : Products.isGood C b
h : Products.eval C a = Products.eval C b
h' : b < a
⊢ Products.eval C b ∈ Submodule.span ℤ (Products.eval C '' {m | m < a})

Next tactic:
exact Submodule.subset_span ⟨b, ⟨h',rfl⟩⟩
theorem linearIndependent_iff_range : LinearIndependent ℤ (GoodProducts.eval C) ↔
    LinearIndependent ℤ (fun (p : range C) ↦ p.1) := by
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
⊢ LinearIndependent ℤ (eval C) ↔ LinearIndependent ℤ fun (p : ↑(range C)) => ↑p

Next tactic:
rw [← @Set.rangeFactorization_eq _ _ (GoodProducts.eval C), ← equiv_toFun_eq_eval C]
theorem linearIndependent_iff_range : LinearIndependent ℤ (GoodProducts.eval C) ↔
    LinearIndependent ℤ (fun (p : range C) ↦ p.1) := by
  rw [← @Set.rangeFactorization_eq _ _ (GoodProducts.eval C), ← equiv_toFun_eq_eval C]
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
⊢ LinearIndependent ℤ (Subtype.val ∘ (equiv_range C).toFun) ↔ LinearIndependent ℤ fun (p : ↑(range C)) => ↑p

Next tactic:
exact linearIndependent_equiv (equiv_range C)
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
⊢ (eval C l) x = if ∀ i ∈ ↑l, ↑x i = true then 1 else 0

Next tactic:
change LocallyConstant.evalMonoidHom x (l.eval C) = _
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
⊢ (LocallyConstant.evalMonoidHom x) (eval C l) = if ∀ i ∈ ↑l, ↑x i = true then 1 else 0

Next tactic:
rw [eval, map_list_prod]
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  

Proof state:
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
⊢ List.prod (List.map (⇑(LocallyConstant.evalMonoidHom x)) (List.map (e C) ↑l)) = if ∀ i ∈ ↑l, ↑x i = true then 1 else 0

Next tactic:
split_ifs with h
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · 

Proof state:
case pos
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∀ i ∈ ↑l, ↑x i = true
⊢ List.prod (List.map (⇑(LocallyConstant.evalMonoidHom x)) (List.map (e C) ↑l)) = 1

Next tactic:
simp only [List.map_map]
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    

Proof state:
case pos
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∀ i ∈ ↑l, ↑x i = true
⊢ List.prod (List.map (⇑(LocallyConstant.evalMonoidHom x) ∘ e C) ↑l) = 1

Next tactic:
apply List.prod_eq_one
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    

Proof state:
case pos.hl
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∀ i ∈ ↑l, ↑x i = true
⊢ ∀ x_1 ∈ List.map (⇑(LocallyConstant.evalMonoidHom x) ∘ e C) ↑l, x_1 = 1

Next tactic:
simp only [List.mem_map, Function.comp_apply]
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    simp only [List.mem_map, Function.comp_apply]
    

Proof state:
case pos.hl
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∀ i ∈ ↑l, ↑x i = true
⊢ ∀ (x_1 : ℤ), (∃ a ∈ ↑l, (LocallyConstant.evalMonoidHom x) (e C a) = x_1) → x_1 = 1

Next tactic:
rintro _ ⟨i, hi, rfl⟩
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    simp only [List.mem_map, Function.comp_apply]
    rintro _ ⟨i, hi, rfl⟩
    

Proof state:
case pos.hl.intro.intro
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∀ i ∈ ↑l, ↑x i = true
i : I
hi : i ∈ ↑l
⊢ (LocallyConstant.evalMonoidHom x) (e C i) = 1

Next tactic:
exact if_pos (h i hi)
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    simp only [List.mem_map, Function.comp_apply]
    rintro _ ⟨i, hi, rfl⟩
    exact if_pos (h i hi)
  · 

Proof state:
case neg
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ¬∀ i ∈ ↑l, ↑x i = true
⊢ List.prod (List.map (⇑(LocallyConstant.evalMonoidHom x)) (List.map (e C) ↑l)) = 0

Next tactic:
simp only [List.map_map, List.prod_eq_zero_iff, List.mem_map, Function.comp_apply]
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    simp only [List.mem_map, Function.comp_apply]
    rintro _ ⟨i, hi, rfl⟩
    exact if_pos (h i hi)
  · simp only [List.map_map, List.prod_eq_zero_iff, List.mem_map, Function.comp_apply]
    

Proof state:
case neg
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ¬∀ i ∈ ↑l, ↑x i = true
⊢ ∃ a ∈ ↑l, (LocallyConstant.evalMonoidHom x) (e C a) = 0

Next tactic:
push_neg at h
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    simp only [List.mem_map, Function.comp_apply]
    rintro _ ⟨i, hi, rfl⟩
    exact if_pos (h i hi)
  · simp only [List.map_map, List.prod_eq_zero_iff, List.mem_map, Function.comp_apply]
    push_neg at h
    

Proof state:
case neg
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∃ i ∈ ↑l, ↑x i ≠ true
⊢ ∃ a ∈ ↑l, (LocallyConstant.evalMonoidHom x) (e C a) = 0

Next tactic:
convert h with i
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    simp only [List.mem_map, Function.comp_apply]
    rintro _ ⟨i, hi, rfl⟩
    exact if_pos (h i hi)
  · simp only [List.map_map, List.prod_eq_zero_iff, List.mem_map, Function.comp_apply]
    push_neg at h
    convert h with i
    

Proof state:
case h.e'_2.h.h.e'_2.a
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∃ i ∈ ↑l, ↑x i ≠ true
i : I
⊢ (LocallyConstant.evalMonoidHom x) (e C i) = 0 ↔ ↑x i ≠ true

Next tactic:
dsimp [LocallyConstant.evalMonoidHom, e]
theorem eval_eq (l : Products I) (x : C) :
    l.eval C x = if ∀ i, i ∈ l.val → (x.val i = true) then 1 else 0 := by
  change LocallyConstant.evalMonoidHom x (l.eval C) = _
  rw [eval, map_list_prod]
  split_ifs with h
  · simp only [List.map_map]
    apply List.prod_eq_one
    simp only [List.mem_map, Function.comp_apply]
    rintro _ ⟨i, hi, rfl⟩
    exact if_pos (h i hi)
  · simp only [List.map_map, List.prod_eq_zero_iff, List.mem_map, Function.comp_apply]
    push_neg at h
    convert h with i
    dsimp [LocallyConstant.evalMonoidHom, e]
    

Proof state:
case h.e'_2.h.h.e'_2.a
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
x : ↑C
h : ∃ i ∈ ↑l, ↑x i ≠ true
i : I
⊢ (if ↑x i = true then 1 else 0) = 0 ↔ ¬↑x i = true

Next tactic:
simp only [ite_eq_right_iff, one_ne_zero]
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  

Proof state:
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
⊢ ⇑(eval (π C J) l) ∘ ProjRestrict C J = ⇑(eval C l)

Next tactic:
ext x
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  

Proof state:
case h
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
⊢ (⇑(eval (π C J) l) ∘ ProjRestrict C J) x = (eval C l) x

Next tactic:
dsimp [ProjRestrict]
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  dsimp [ProjRestrict]
  

Proof state:
case h
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
⊢ (eval (π C J) l) (Set.MapsTo.restrict (Proj J) C (π C J) (_ : Set.MapsTo (Proj J) C (Proj J '' C)) x) = (eval C l) x

Next tactic:
rw [Products.eval_eq, Products.eval_eq]
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  dsimp [ProjRestrict]
  rw [Products.eval_eq, Products.eval_eq]
  

Proof state:
case h
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
⊢ (if ∀ i ∈ ↑l, ↑(Set.MapsTo.restrict (Proj J) C (π C J) (_ : Set.MapsTo (Proj J) C (Proj J '' C)) x) i = true then 1
    else 0) =
    if ∀ i ∈ ↑l, ↑x i = true then 1 else 0

Next tactic:
congr
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  dsimp [ProjRestrict]
  rw [Products.eval_eq, Products.eval_eq]
  congr
  

Proof state:
case h.e_c
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
⊢ (∀ i ∈ ↑l, ↑(Set.MapsTo.restrict (Proj J) C (π C J) (_ : Set.MapsTo (Proj J) C (Proj J '' C)) x) i = true) =
    ∀ i ∈ ↑l, ↑x i = true

Next tactic:
apply forall_congr
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  dsimp [ProjRestrict]
  rw [Products.eval_eq, Products.eval_eq]
  congr
  apply forall_congr; 

Proof state:
case h.e_c.h
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
⊢ ∀ (a : I),
    (a ∈ ↑l → ↑(Set.MapsTo.restrict (Proj J) C (π C J) (_ : Set.MapsTo (Proj J) C (Proj J '' C)) x) a = true) =
      (a ∈ ↑l → ↑x a = true)

Next tactic:
intro i
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  dsimp [ProjRestrict]
  rw [Products.eval_eq, Products.eval_eq]
  congr
  apply forall_congr; intro i
  

Proof state:
case h.e_c.h
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
i : I
⊢ (i ∈ ↑l → ↑(Set.MapsTo.restrict (Proj J) C (π C J) (_ : Set.MapsTo (Proj J) C (Proj J '' C)) x) i = true) =
    (i ∈ ↑l → ↑x i = true)

Next tactic:
apply forall_congr
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  dsimp [ProjRestrict]
  rw [Products.eval_eq, Products.eval_eq]
  congr
  apply forall_congr; intro i
  apply forall_congr; 

Proof state:
case h.e_c.h.h
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
i : I
⊢ i ∈ ↑l →
    (↑(Set.MapsTo.restrict (Proj J) C (π C J) (_ : Set.MapsTo (Proj J) C (Proj J '' C)) x) i = true) = (↑x i = true)

Next tactic:
intro hi
theorem evalFacProp {l : Products I} (J : I → Prop)
    (h : ∀ a, a ∈ l.val → J a) [∀ j, Decidable (J j)] :
    l.eval (π C J) ∘ ProjRestrict C J = l.eval C := by
  ext x
  dsimp [ProjRestrict]
  rw [Products.eval_eq, Products.eval_eq]
  congr
  apply forall_congr; intro i
  apply forall_congr; intro hi
  

Proof state:
case h.e_c.h.h
I : Type u
inst✝³ : Inhabited I
inst✝² : LinearOrder I
inst✝¹ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
l : Products I
J : I → Prop
h : ∀ a ∈ ↑l, J a
inst✝ : (j : I) → Decidable (J j)
x : ↑C
i : I
hi : i ∈ ↑l
⊢ (↑(Set.MapsTo.restrict (Proj J) C (π C J) (_ : Set.MapsTo (Proj J) C (Proj J '' C)) x) i = true) = (↑x i = true)

Next tactic:
simp [h i hi, Proj]