l3lab/ntp-mathlib huggingface dataset:
/-- An arbitrary product `e C i₁ * e C i₂ * ... * e C iᵣ` is in the ℤ-span of the good products. -/
theorem eval_mem_span_goodProducts (l : Products I) :
    l.eval C ∈ span ℤ (Set.range (GoodProducts.eval C)) := by
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    exact ⟨⟨l, hl⟩, rfl⟩
  · simp only [Products.isGood, not_not] at hl
    suffices : Products.eval C '' {m | m < l} ⊆ span ℤ (Set.range (GoodProducts.eval C))
    · rw [← span_le] at this
      exact this hl
    rintro a ⟨m, hm, rfl⟩
    

Proof state:
case this.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
L : Products I → Prop := fun m => eval C m ∈ Submodule.span ℤ (Set.range (GoodProducts.eval C))
l : Products I
h : ∀ y < l, L y
hl : eval C l ∈ Submodule.span ℤ (eval C '' {m | m < l})
m : Products I
hm : m ∈ {m | m < l}
⊢ eval C m ∈ ↑(Submodule.span ℤ (Set.range (GoodProducts.eval C)))

Next tactic:
exact h m hm
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.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)
⊢ ⊤ ≤ Submodule.span ℤ (Set.range (eval C)) ↔ ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))

Next tactic:
refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans 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)
h : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
⊢ Submodule.span ℤ (Set.range (Products.eval C)) ≤ Submodule.span ℤ (Set.range (eval C))

Next tactic:
rw [span_le]
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  

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)
h : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
⊢ Set.range (Products.eval C) ⊆ ↑(Submodule.span ℤ (Set.range (eval C)))

Next tactic:
rintro f ⟨l, rfl⟩
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  

Proof state:
case intro
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l : Products I
⊢ Products.eval C l ∈ ↑(Submodule.span ℤ (Set.range (eval C)))

Next tactic:
let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  

Proof state:
case intro
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
⊢ Products.eval C l ∈ ↑(Submodule.span ℤ (Set.range (eval C)))

Next tactic:
suffices L l by assumption
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l 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)
h : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
this : L l
⊢ Products.eval C l ∈ ↑(Submodule.span ℤ (Set.range (eval C)))

Next tactic:
assumption
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  

Proof state:
case intro
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
⊢ L l

Next tactic:
apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  

Proof state:
case intro.a
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
⊢ ∀ (x : Products I), (∀ y < x, L y) → L x

Next tactic:
intro l h
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  

Proof state:
case intro.a
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
⊢ L l

Next tactic:
dsimp
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  

Proof state:
case intro.a
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
⊢ Products.eval C l ∈ Submodule.span ℤ (Set.range (eval C))

Next tactic:
by_cases hl : l.isGood C
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · 

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)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : Products.isGood C l
⊢ Products.eval C l ∈ Submodule.span ℤ (Set.range (eval C))

Next tactic:
apply subset_span
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    

Proof state:
case pos.a
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : Products.isGood C l
⊢ Products.eval C l ∈ Set.range (eval C)

Next tactic:
exact ⟨⟨l, hl⟩, rfl⟩
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    exact ⟨⟨l, hl⟩, rfl⟩
  · 

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)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : ¬Products.isGood C l
⊢ Products.eval C l ∈ Submodule.span ℤ (Set.range (eval C))

Next tactic:
simp only [Products.isGood, not_not] at hl
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    exact ⟨⟨l, hl⟩, rfl⟩
  · simp only [Products.isGood, not_not] at hl
    

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)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : Products.eval C l ∈ Submodule.span ℤ (Products.eval C '' {m | m < l})
⊢ Products.eval C l ∈ Submodule.span ℤ (Set.range (eval C))

Next tactic:
suffices : Products.eval C '' {m | m < l} ⊆ span ℤ (Set.range (GoodProducts.eval C))
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    exact ⟨⟨l, hl⟩, rfl⟩
  · simp only [Products.isGood, not_not] at hl
    suffices : Products.eval C '' {m | m < l} ⊆ span ℤ (Set.range (GoodProducts.eval C))
    · 

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)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : Products.eval C l ∈ Submodule.span ℤ (Products.eval C '' {m | m < l})
this : Products.eval C '' {m | m < l} ⊆ ↑(Submodule.span ℤ (Set.range (eval C)))
⊢ Products.eval C l ∈ Submodule.span ℤ (Set.range (eval C))

Next tactic:
rw [← span_le] at this
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    exact ⟨⟨l, hl⟩, rfl⟩
  · simp only [Products.isGood, not_not] at hl
    suffices : Products.eval C '' {m | m < l} ⊆ span ℤ (Set.range (GoodProducts.eval C))
    · rw [← span_le] at this
      

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)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : Products.eval C l ∈ Submodule.span ℤ (Products.eval C '' {m | m < l})
this : Submodule.span ℤ (Products.eval C '' {m | m < l}) ≤ Submodule.span ℤ (Set.range (eval C))
⊢ Products.eval C l ∈ Submodule.span ℤ (Set.range (eval C))

Next tactic:
exact this hl
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    exact ⟨⟨l, hl⟩, rfl⟩
  · simp only [Products.isGood, not_not] at hl
    suffices : Products.eval C '' {m | m < l} ⊆ span ℤ (Set.range (GoodProducts.eval C))
    · rw [← span_le] at this
      exact this hl
    

Proof state:
case this
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : Products.eval C l ∈ Submodule.span ℤ (Products.eval C '' {m | m < l})
⊢ Products.eval C '' {m | m < l} ⊆ ↑(Submodule.span ℤ (Set.range (eval C)))

Next tactic:
rintro a ⟨m, hm, rfl⟩
/-- The good products span `LocallyConstant C ℤ` if and only all the products do. -/
theorem GoodProducts.span_iff_products : ⊤ ≤ span ℤ (Set.range (eval C)) ↔
    ⊤ ≤ span ℤ (Set.range (Products.eval C)) := by
  refine ⟨fun h ↦ le_trans h (span_mono (fun a ⟨b, hb⟩ ↦ ⟨b.val, hb⟩)), fun h ↦ le_trans h ?_⟩
  rw [span_le]
  rintro f ⟨l, rfl⟩
  let L : Products I → Prop := fun m ↦ m.eval C ∈ span ℤ (Set.range (GoodProducts.eval C))
  suffices L l by assumption
  apply IsWellFounded.induction (·<· : Products I → Products I → Prop)
  intro l h
  dsimp
  by_cases hl : l.isGood C
  · apply subset_span
    exact ⟨⟨l, hl⟩, rfl⟩
  · simp only [Products.isGood, not_not] at hl
    suffices : Products.eval C '' {m | m < l} ⊆ span ℤ (Set.range (GoodProducts.eval C))
    · rw [← span_le] at this
      exact this hl
    rintro a ⟨m, hm, rfl⟩
    

Proof state:
case this.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)
h✝ : ⊤ ≤ Submodule.span ℤ (Set.range (Products.eval C))
l✝ : Products I
L : Products I → Prop := fun m => Products.eval C m ∈ Submodule.span ℤ (Set.range (eval C))
l : Products I
h : ∀ y < l, L y
hl : Products.eval C l ∈ Submodule.span ℤ (Products.eval C '' {m | m < l})
m : Products I
hm : m ∈ {m | m < l}
⊢ Products.eval C m ∈ ↑(Submodule.span ℤ (Set.range (eval C)))

Next tactic:
exact h m hm
theorem eval_eq_πJ (l : Products I) (hl : l.isGood (π C (· ∈ s))) :
    l.eval C = πJ C s (l.eval (π C (· ∈ s))) := 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)
s : Finset I
l : Products I
hl : Products.isGood (π C fun x => x ∈ s) l
⊢ Products.eval C l = (πJ C s) (Products.eval (π C fun x => x ∈ s) l)

Next tactic:
ext f
theorem eval_eq_πJ (l : Products I) (hl : l.isGood (π C (· ∈ s))) :
    l.eval C = πJ C s (l.eval (π C (· ∈ s))) := by
  ext f
  

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)
s : Finset I
l : Products I
hl : Products.isGood (π C fun x => x ∈ s) l
f : ↑C
⊢ (Products.eval C l) f = ((πJ C s) (Products.eval (π C fun x => x ∈ s) l)) f

Next tactic:
simp only [πJ, LocallyConstant.comapₗ, LinearMap.coe_mk, AddHom.coe_mk,
    (continuous_projRestrict C (· ∈ s)), LocallyConstant.coe_comap, Function.comp_apply]
theorem eval_eq_πJ (l : Products I) (hl : l.isGood (π C (· ∈ s))) :
    l.eval C = πJ C s (l.eval (π C (· ∈ s))) := by
  ext f
  simp only [πJ, LocallyConstant.comapₗ, LinearMap.coe_mk, AddHom.coe_mk,
    (continuous_projRestrict C (· ∈ s)), LocallyConstant.coe_comap, Function.comp_apply]
  

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)
s : Finset I
l : Products I
hl : Products.isGood (π C fun x => x ∈ s) l
f : ↑C
⊢ (Products.eval C l) f = (Products.eval (π C fun x => x ∈ s) l) (ProjRestrict C (fun x => x ∈ s) f)

Next tactic:
exact (congr_fun (Products.evalFacProp C (· ∈ s) (Products.prop_of_isGood  C (· ∈ s) hl)) _).symm
/-- `π C (· ∈ s)` is finite for a finite set `s`. -/
noncomputable
instance : Fintype (π C (· ∈ s)) := 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)
s : Finset I
⊢ Fintype ↑(π C fun x => x ∈ s)

Next tactic:
let f : π C (· ∈ s) → (s → Bool) := fun x j ↦ x.val j.val
/-- `π C (· ∈ s)` is finite for a finite set `s`. -/
noncomputable
instance : Fintype (π C (· ∈ s)) := by
  let f : π C (· ∈ s) → (s → Bool) := fun x j ↦ x.val j.val
  

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)
s : Finset I
f : ↑(π C fun x => x ∈ s) → { x // x ∈ s } → Bool := fun x j => ↑x ↑j
⊢ Fintype ↑(π C fun x => x ∈ s)

Next tactic:
refine Fintype.ofInjective f ?_
/-- `π C (· ∈ s)` is finite for a finite set `s`. -/
noncomputable
instance : Fintype (π C (· ∈ s)) := by
  let f : π C (· ∈ s) → (s → Bool) := fun x j ↦ x.val j.val
  refine Fintype.ofInjective f ?_
  

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)
s : Finset I
f : ↑(π C fun x => x ∈ s) → { x // x ∈ s } → Bool := fun x j => ↑x ↑j
⊢ Function.Injective f

Next tactic:
intro ⟨_, x, hx, rfl⟩ ⟨_, y, hy, rfl⟩ h
/-- `π C (· ∈ s)` is finite for a finite set `s`. -/
noncomputable
instance : Fintype (π C (· ∈ s)) := by
  let f : π C (· ∈ s) → (s → Bool) := fun x j ↦ x.val j.val
  refine Fintype.ofInjective f ?_
  intro ⟨_, x, hx, rfl⟩ ⟨_, y, hy, rfl⟩ 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)
s : Finset I
f : ↑(π C fun x => x ∈ s) → { x // x ∈ s } → Bool := fun x j => ↑x ↑j
x : I → Bool
hx : x ∈ C
y : I → Bool
hy : y ∈ C
h :
  f { val := Proj (fun x => x ∈ s) x, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) x) } =
    f { val := Proj (fun x => x ∈ s) y, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) y) }
⊢ { val := Proj (fun x => x ∈ s) x, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) x) } =
    { val := Proj (fun x => x ∈ s) y, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) y) }

Next tactic:
ext i
/-- `π C (· ∈ s)` is finite for a finite set `s`. -/
noncomputable
instance : Fintype (π C (· ∈ s)) := by
  let f : π C (· ∈ s) → (s → Bool) := fun x j ↦ x.val j.val
  refine Fintype.ofInjective f ?_
  intro ⟨_, x, hx, rfl⟩ ⟨_, y, hy, rfl⟩ h
  ext i
  

Proof state:
case a.h
I : Type u
inst✝² : Inhabited I
inst✝¹ : LinearOrder I
inst✝ : IsWellOrder I fun x x_1 => x < x_1
C : Set (I → Bool)
s : Finset I
f : ↑(π C fun x => x ∈ s) → { x // x ∈ s } → Bool := fun x j => ↑x ↑j
x : I → Bool
hx : x ∈ C
y : I → Bool
hy : y ∈ C
h :
  f { val := Proj (fun x => x ∈ s) x, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) x) } =
    f { val := Proj (fun x => x ∈ s) y, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) y) }
i : I
⊢ ↑{ val := Proj (fun x => x ∈ s) x, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) x) } i =
    ↑{ val := Proj (fun x => x ∈ s) y, property := (_ : ∃ a ∈ C, Proj (fun x => x ∈ s) a = Proj (fun x => x ∈ s) y) } i

Next tactic:
by_cases hi : i ∈ s