l3lab/ntp-mathlib huggingface dataset:
theorem filter_snd_eq_antidiagonal (n m : A) [DecidablePred (· = m)] [Decidable (m ≤ n)] :
    filter (fun x : A × A ↦ x.snd = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅ := by
  

Proof state:
A : Type u_1
inst✝⁶ : CanonicallyOrderedAddCommMonoid A
inst✝⁵ : Sub A
inst✝⁴ : OrderedSub A
inst✝³ : ContravariantClass A A (fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1
inst✝² : HasAntidiagonal A
n m : A
inst✝¹ : DecidablePred fun x => x = m
inst✝ : Decidable (m ≤ n)
⊢ filter (fun x => x.2 = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅

Next tactic:
have : (fun x : A × A ↦ (x.snd = m)) ∘ Prod.swap = fun x : A × A ↦ x.fst = m := by
    ext; simp
theorem filter_snd_eq_antidiagonal (n m : A) [DecidablePred (· = m)] [Decidable (m ≤ n)] :
    filter (fun x : A × A ↦ x.snd = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅ := by
  have : (fun x : A × A ↦ (x.snd = m)) ∘ Prod.swap = fun x : A × A ↦ x.fst = m := by
    

Proof state:
A : Type u_1
inst✝⁶ : CanonicallyOrderedAddCommMonoid A
inst✝⁵ : Sub A
inst✝⁴ : OrderedSub A
inst✝³ : ContravariantClass A A (fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1
inst✝² : HasAntidiagonal A
n m : A
inst✝¹ : DecidablePred fun x => x = m
inst✝ : Decidable (m ≤ n)
⊢ (fun x => x.2 = m) ∘ Prod.swap = fun x => x.1 = m

Next tactic:
ext
theorem filter_snd_eq_antidiagonal (n m : A) [DecidablePred (· = m)] [Decidable (m ≤ n)] :
    filter (fun x : A × A ↦ x.snd = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅ := by
  have : (fun x : A × A ↦ (x.snd = m)) ∘ Prod.swap = fun x : A × A ↦ x.fst = m := by
    ext; 

Proof state:
case h.a
A : Type u_1
inst✝⁶ : CanonicallyOrderedAddCommMonoid A
inst✝⁵ : Sub A
inst✝⁴ : OrderedSub A
inst✝³ : ContravariantClass A A (fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1
inst✝² : HasAntidiagonal A
n m : A
inst✝¹ : DecidablePred fun x => x = m
inst✝ : Decidable (m ≤ n)
x✝ : A × A
⊢ ((fun x => x.2 = m) ∘ Prod.swap) x✝ ↔ x✝.1 = m

Next tactic:
simp
theorem filter_snd_eq_antidiagonal (n m : A) [DecidablePred (· = m)] [Decidable (m ≤ n)] :
    filter (fun x : A × A ↦ x.snd = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅ := by
  have : (fun x : A × A ↦ (x.snd = m)) ∘ Prod.swap = fun x : A × A ↦ x.fst = m := by
    ext; simp
  

Proof state:
A : Type u_1
inst✝⁶ : CanonicallyOrderedAddCommMonoid A
inst✝⁵ : Sub A
inst✝⁴ : OrderedSub A
inst✝³ : ContravariantClass A A (fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1
inst✝² : HasAntidiagonal A
n m : A
inst✝¹ : DecidablePred fun x => x = m
inst✝ : Decidable (m ≤ n)
this : (fun x => x.2 = m) ∘ Prod.swap = fun x => x.1 = m
⊢ filter (fun x => x.2 = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅

Next tactic:
rw [← map_swap_antidiagonal, filter_map]
theorem filter_snd_eq_antidiagonal (n m : A) [DecidablePred (· = m)] [Decidable (m ≤ n)] :
    filter (fun x : A × A ↦ x.snd = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅ := by
  have : (fun x : A × A ↦ (x.snd = m)) ∘ Prod.swap = fun x : A × A ↦ x.fst = m := by
    ext; simp
  rw [← map_swap_antidiagonal, filter_map]
  

Proof state:
A : Type u_1
inst✝⁶ : CanonicallyOrderedAddCommMonoid A
inst✝⁵ : Sub A
inst✝⁴ : OrderedSub A
inst✝³ : ContravariantClass A A (fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1
inst✝² : HasAntidiagonal A
n m : A
inst✝¹ : DecidablePred fun x => x = m
inst✝ : Decidable (m ≤ n)
this : (fun x => x.2 = m) ∘ Prod.swap = fun x => x.1 = m
⊢ map { toFun := Prod.swap, inj' := (_ : Injective Prod.swap) }
      (filter ((fun x => x.2 = m) ∘ ⇑{ toFun := Prod.swap, inj' := (_ : Injective Prod.swap) }) (antidiagonal n)) =
    if m ≤ n then {(n - m, m)} else ∅

Next tactic:
simp [this, filter_fst_eq_antidiagonal, apply_ite (Finset.map _)]
/-- The disjoint union of antidiagonals `Σ (n : A), antidiagonal n` is equivalent to the product
    `A × A`. This is such an equivalence, obtained by mapping `(n, (k, l))` to `(k, l)`. -/
@[simps]
def sigmaAntidiagonalEquivProd [AddMonoid A] [HasAntidiagonal A] :
    (Σ n : A, antidiagonal n) ≃ A × A where
  toFun x := x.2
  invFun x := ⟨x.1 + x.2, x, mem_antidiagonal.mpr rfl⟩
  left_inv := by
    

Proof state:
A : Type u_1
inst✝¹ : AddMonoid A
inst✝ : HasAntidiagonal A
⊢ LeftInverse (fun x => { fst := x.1 + x.2, snd := { val := x, property := (_ : x ∈ antidiagonal (x.1 + x.2)) } })
    fun x => ↑x.snd

Next tactic:
rintro ⟨n, ⟨k, l⟩, h⟩
/-- The disjoint union of antidiagonals `Σ (n : A), antidiagonal n` is equivalent to the product
    `A × A`. This is such an equivalence, obtained by mapping `(n, (k, l))` to `(k, l)`. -/
@[simps]
def sigmaAntidiagonalEquivProd [AddMonoid A] [HasAntidiagonal A] :
    (Σ n : A, antidiagonal n) ≃ A × A where
  toFun x := x.2
  invFun x := ⟨x.1 + x.2, x, mem_antidiagonal.mpr rfl⟩
  left_inv := by
    rintro ⟨n, ⟨k, l⟩, h⟩
    

Proof state:
case mk.mk.mk
A : Type u_1
inst✝¹ : AddMonoid A
inst✝ : HasAntidiagonal A
n k l : A
h : (k, l) ∈ antidiagonal n
⊢ (fun x => { fst := x.1 + x.2, snd := { val := x, property := (_ : x ∈ antidiagonal (x.1 + x.2)) } })
      ((fun x => ↑x.snd) { fst := n, snd := { val := (k, l), property := h } }) =
    { fst := n, snd := { val := (k, l), property := h } }

Next tactic:
rw [mem_antidiagonal] at h
/-- The disjoint union of antidiagonals `Σ (n : A), antidiagonal n` is equivalent to the product
    `A × A`. This is such an equivalence, obtained by mapping `(n, (k, l))` to `(k, l)`. -/
@[simps]
def sigmaAntidiagonalEquivProd [AddMonoid A] [HasAntidiagonal A] :
    (Σ n : A, antidiagonal n) ≃ A × A where
  toFun x := x.2
  invFun x := ⟨x.1 + x.2, x, mem_antidiagonal.mpr rfl⟩
  left_inv := by
    rintro ⟨n, ⟨k, l⟩, h⟩
    rw [mem_antidiagonal] at h
    

Proof state:
case mk.mk.mk
A : Type u_1
inst✝¹ : AddMonoid A
inst✝ : HasAntidiagonal A
n k l : A
h✝ : (k, l) ∈ antidiagonal n
h : (k, l).1 + (k, l).2 = n
⊢ (fun x => { fst := x.1 + x.2, snd := { val := x, property := (_ : x ∈ antidiagonal (x.1 + x.2)) } })
      ((fun x => ↑x.snd) { fst := n, snd := { val := (k, l), property := h✝ } }) =
    { fst := n, snd := { val := (k, l), property := h✝ } }

Next tactic:
exact Sigma.subtype_ext h rfl
/-- In a canonically ordered add monoid, the antidiagonal can be construct by filtering.

Note that this is not an instance, as for some times a more efficient algorithm is available. -/
abbrev antidiagonalOfLocallyFinite : HasAntidiagonal A where
  antidiagonal n := Finset.filter (fun uv => uv.fst + uv.snd = n) (Finset.product (Iic n) (Iic n))
  mem_antidiagonal {n} {a} := by
    

Proof state:
A✝ : Type u_1
A : Type u_2
inst✝² : CanonicallyOrderedAddCommMonoid A
inst✝¹ : LocallyFiniteOrder A
inst✝ : DecidableEq A
n : A
a : A × A
⊢ a ∈ (fun n => filter (fun uv => uv.1 + uv.2 = n) (Finset.product (Iic n) (Iic n))) n ↔ a.1 + a.2 = n

Next tactic:
simp only [Prod.forall, mem_filter, and_iff_right_iff_imp]
/-- In a canonically ordered add monoid, the antidiagonal can be construct by filtering.

Note that this is not an instance, as for some times a more efficient algorithm is available. -/
abbrev antidiagonalOfLocallyFinite : HasAntidiagonal A where
  antidiagonal n := Finset.filter (fun uv => uv.fst + uv.snd = n) (Finset.product (Iic n) (Iic n))
  mem_antidiagonal {n} {a} := by
    simp only [Prod.forall, mem_filter, and_iff_right_iff_imp]
    

Proof state:
A✝ : Type u_1
A : Type u_2
inst✝² : CanonicallyOrderedAddCommMonoid A
inst✝¹ : LocallyFiniteOrder A
inst✝ : DecidableEq A
n : A
a : A × A
⊢ a.1 + a.2 = n → a ∈ Finset.product (Iic n) (Iic n)

Next tactic:
intro h
/-- In a canonically ordered add monoid, the antidiagonal can be construct by filtering.

Note that this is not an instance, as for some times a more efficient algorithm is available. -/
abbrev antidiagonalOfLocallyFinite : HasAntidiagonal A where
  antidiagonal n := Finset.filter (fun uv => uv.fst + uv.snd = n) (Finset.product (Iic n) (Iic n))
  mem_antidiagonal {n} {a} := by
    simp only [Prod.forall, mem_filter, and_iff_right_iff_imp]
    intro h; 

Proof state:
A✝ : Type u_1
A : Type u_2
inst✝² : CanonicallyOrderedAddCommMonoid A
inst✝¹ : LocallyFiniteOrder A
inst✝ : DecidableEq A
n : A
a : A × A
h : a.1 + a.2 = n
⊢ a ∈ Finset.product (Iic n) (Iic n)

Next tactic:
rw [← h]
/-- In a canonically ordered add monoid, the antidiagonal can be construct by filtering.

Note that this is not an instance, as for some times a more efficient algorithm is available. -/
abbrev antidiagonalOfLocallyFinite : HasAntidiagonal A where
  antidiagonal n := Finset.filter (fun uv => uv.fst + uv.snd = n) (Finset.product (Iic n) (Iic n))
  mem_antidiagonal {n} {a} := by
    simp only [Prod.forall, mem_filter, and_iff_right_iff_imp]
    intro h; rw [← h]
    

Proof state:
A✝ : Type u_1
A : Type u_2
inst✝² : CanonicallyOrderedAddCommMonoid A
inst✝¹ : LocallyFiniteOrder A
inst✝ : DecidableEq A
n : A
a : A × A
h : a.1 + a.2 = n
⊢ a ∈ Finset.product (Iic (a.1 + a.2)) (Iic (a.1 + a.2))

Next tactic:
erw [mem_product, mem_Iic, mem_Iic]
/-- In a canonically ordered add monoid, the antidiagonal can be construct by filtering.

Note that this is not an instance, as for some times a more efficient algorithm is available. -/
abbrev antidiagonalOfLocallyFinite : HasAntidiagonal A where
  antidiagonal n := Finset.filter (fun uv => uv.fst + uv.snd = n) (Finset.product (Iic n) (Iic n))
  mem_antidiagonal {n} {a} := by
    simp only [Prod.forall, mem_filter, and_iff_right_iff_imp]
    intro h; rw [← h]
    erw [mem_product, mem_Iic, mem_Iic]
    

Proof state:
A✝ : Type u_1
A : Type u_2
inst✝² : CanonicallyOrderedAddCommMonoid A
inst✝¹ : LocallyFiniteOrder A
inst✝ : DecidableEq A
n : A
a : A × A
h : a.1 + a.2 = n
⊢ a.1 ≤ a.1 + a.2 ∧ a.2 ≤ a.1 + a.2

Next tactic:
exact ⟨le_self_add, le_add_self⟩
instance (n : ℕ) : DecidableEq (Language.ring.Functions n) := by
  

Proof state:
α : Type u_1
n : ℕ
⊢ DecidableEq (Functions ring n)

Next tactic:
dsimp [Language.ring]
instance (n : ℕ) : DecidableEq (Language.ring.Functions n) := by
  dsimp [Language.ring]; 

Proof state:
α : Type u_1
n : ℕ
⊢ DecidableEq (ringFunc n)

Next tactic:
infer_instance
instance (n : ℕ) : DecidableEq (Language.ring.Relations n) := by
  

Proof state:
α : Type u_1
n : ℕ
⊢ DecidableEq (Relations ring n)

Next tactic:
dsimp [Language.ring]
instance (n : ℕ) : DecidableEq (Language.ring.Relations n) := by
  dsimp [Language.ring]; 

Proof state:
α : Type u_1
n : ℕ
⊢ DecidableEq Empty

Next tactic:
infer_instance
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    

Proof state:
α : Type u_1
⊢ Multiset.Nodup
    ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
        Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]

Next tactic:
dsimp [Language.Symbols]
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; 

Proof state:
α : Type u_1
⊢ Multiset.Nodup
    ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
        Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]

Next tactic:
decide
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    

Proof state:
α : Type u_1
⊢ ∀ (x : Symbols ring),
    x ∈
      {
        val :=
          ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
              Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
        nodup :=
          (_ :
            Multiset.Nodup
              ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                  Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
intro x
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    

Proof state:
α : Type u_1
x : Symbols ring
⊢ x ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
dsimp [Language.Symbols]
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    

Proof state:
α : Type u_1
x : Symbols ring
⊢ x ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
rcases x with ⟨_, f⟩ | ⟨_, f⟩
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    rcases x with ⟨_, f⟩ | ⟨_, f⟩
    · 

Proof state:
case inl.mk
α : Type u_1
fst✝ : ℕ
f : Functions ring fst✝
⊢ Sum.inl { fst := fst✝, snd := f } ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
cases f
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    rcases x with ⟨_, f⟩ | ⟨_, f⟩
    · cases f <;> 

Proof state:
case inl.mk.add
α : Type u_1
⊢ Sum.inl { fst := 2, snd := add } ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
decide
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    rcases x with ⟨_, f⟩ | ⟨_, f⟩
    · cases f <;> 

Proof state:
case inl.mk.mul
α : Type u_1
⊢ Sum.inl { fst := 2, snd := mul } ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
decide
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    rcases x with ⟨_, f⟩ | ⟨_, f⟩
    · cases f <;> 

Proof state:
case inl.mk.neg
α : Type u_1
⊢ Sum.inl { fst := 1, snd := neg } ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
decide
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    rcases x with ⟨_, f⟩ | ⟨_, f⟩
    · cases f <;> 

Proof state:
case inl.mk.zero
α : Type u_1
⊢ Sum.inl { fst := 0, snd := zero } ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
decide
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    rcases x with ⟨_, f⟩ | ⟨_, f⟩
    · cases f <;> 

Proof state:
case inl.mk.one
α : Type u_1
⊢ Sum.inl { fst := 0, snd := one } ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
decide
instance : Fintype Language.ring.Symbols :=
  ⟨⟨Multiset.ofList
      [Sum.inl ⟨2, .add⟩,
       Sum.inl ⟨2, .mul⟩,
       Sum.inl ⟨1, .neg⟩,
       Sum.inl ⟨0, .zero⟩,
       Sum.inl ⟨0, .one⟩], by
    dsimp [Language.Symbols]; decide⟩, by
    intro x
    dsimp [Language.Symbols]
    rcases x with ⟨_, f⟩ | ⟨_, f⟩
    · cases f <;> decide
    · 

Proof state:
case inr.mk
α : Type u_1
fst✝ : ℕ
f : Relations ring fst✝
⊢ Sum.inr { fst := fst✝, snd := f } ∈
    {
      val :=
        ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
            Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }],
      nodup :=
        (_ :
          Multiset.Nodup
            ↑[Sum.inl { fst := 2, snd := add }, Sum.inl { fst := 2, snd := mul }, Sum.inl { fst := 1, snd := neg },
                Sum.inl { fst := 0, snd := zero }, Sum.inl { fst := 0, snd := one }]) }

Next tactic:
cases f
@[simp]
theorem card_ring : card Language.ring = 5 := by
  

Proof state:
α : Type u_1
⊢ card ring = 5

Next tactic:
have : Fintype.card Language.ring.Symbols = 5 := rfl
@[simp]
theorem card_ring : card Language.ring = 5 := by
  have : Fintype.card Language.ring.Symbols = 5 := rfl
  

Proof state:
α : Type u_1
this : Fintype.card (Symbols ring) = 5
⊢ card ring = 5

Next tactic:
simp [Language.card, this]
@[simp]
theorem realize_add (x y : ring.Term α) (v : α → R) :
    Term.realize v (x + y) = Term.realize v x + Term.realize v y := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝⁵ : Add R
inst✝⁴ : Mul R
inst✝³ : Neg R
inst✝² : One R
inst✝¹ : Zero R
inst✝ : CompatibleRing R
x y : Term ring α
v : α → R
⊢ Term.realize v (x + y) = Term.realize v x + Term.realize v y

Next tactic:
simp [add_def, funMap_add]
@[simp]
theorem realize_mul (x y : ring.Term α) (v : α → R) :
    Term.realize v (x * y) = Term.realize v x * Term.realize v y := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝⁵ : Add R
inst✝⁴ : Mul R
inst✝³ : Neg R
inst✝² : One R
inst✝¹ : Zero R
inst✝ : CompatibleRing R
x y : Term ring α
v : α → R
⊢ Term.realize v (x * y) = Term.realize v x * Term.realize v y

Next tactic:
simp [mul_def, funMap_mul]
@[simp]
theorem realize_neg (x : ring.Term α) (v : α → R) :
    Term.realize v (-x) = -Term.realize v x := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝⁵ : Add R
inst✝⁴ : Mul R
inst✝³ : Neg R
inst✝² : One R
inst✝¹ : Zero R
inst✝ : CompatibleRing R
x : Term ring α
v : α → R
⊢ Term.realize v (-x) = -Term.realize v x

Next tactic:
simp [neg_def, funMap_neg]
@[simp]
theorem realize_zero (v : α → R) : Term.realize v (0 : ring.Term α) = 0 := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝⁵ : Add R
inst✝⁴ : Mul R
inst✝³ : Neg R
inst✝² : One R
inst✝¹ : Zero R
inst✝ : CompatibleRing R
v : α → R
⊢ Term.realize v 0 = 0

Next tactic:
simp [zero_def, funMap_zero, constantMap]
@[simp]
theorem realize_one (v : α → R) : Term.realize v (1 : ring.Term α) = 1 := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝⁵ : Add R
inst✝⁴ : Mul R
inst✝³ : Neg R
inst✝² : One R
inst✝¹ : Zero R
inst✝ : CompatibleRing R
v : α → R
⊢ Term.realize v 1 = 1

Next tactic:
simp [one_def, funMap_one, constantMap]
/-- An isomorphism in the language of rings is a ring isomorphism -/
def languageEquivEquivRingEquiv {R S : Type*}
    [NonAssocRing R] [NonAssocRing S]
    [CompatibleRing R] [CompatibleRing S] :
    (Language.ring.Equiv R S) ≃ (R ≃+* S) :=
  { toFun := fun f =>
    { f with
      map_add' := by
        intro x y
        simpa using f.map_fun addFunc ![x, y]
      map_mul' := by
        

Proof state:
α : Type u_1
R : Type u_2
S : Type u_3
inst✝³ : NonAssocRing R
inst✝² : NonAssocRing S
inst✝¹ : CompatibleRing R
inst✝ : CompatibleRing S
f : R ≃[ring] S
⊢ ∀ (x y : R), Equiv.toFun f.toEquiv (x * y) = Equiv.toFun f.toEquiv x * Equiv.toFun f.toEquiv y

Next tactic:
intro x y
/-- An isomorphism in the language of rings is a ring isomorphism -/
def languageEquivEquivRingEquiv {R S : Type*}
    [NonAssocRing R] [NonAssocRing S]
    [CompatibleRing R] [CompatibleRing S] :
    (Language.ring.Equiv R S) ≃ (R ≃+* S) :=
  { toFun := fun f =>
    { f with
      map_add' := by
        intro x y
        simpa using f.map_fun addFunc ![x, y]
      map_mul' := by
        intro x y
        

Proof state:
α : Type u_1
R : Type u_2
S : Type u_3
inst✝³ : NonAssocRing R
inst✝² : NonAssocRing S
inst✝¹ : CompatibleRing R
inst✝ : CompatibleRing S
f : R ≃[ring] S
x y : R
⊢ Equiv.toFun f.toEquiv (x * y) = Equiv.toFun f.toEquiv x * Equiv.toFun f.toEquiv y

Next tactic:
simpa using f.map_fun mulFunc ![x, y]
/-- An isomorphism in the language of rings is a ring isomorphism -/
def languageEquivEquivRingEquiv {R S : Type*}
    [NonAssocRing R] [NonAssocRing S]
    [CompatibleRing R] [CompatibleRing S] :
    (Language.ring.Equiv R S) ≃ (R ≃+* S) :=
  { toFun := fun f =>
    { f with
      map_add' := by
        

Proof state:
α : Type u_1
R : Type u_2
S : Type u_3
inst✝³ : NonAssocRing R
inst✝² : NonAssocRing S
inst✝¹ : CompatibleRing R
inst✝ : CompatibleRing S
f : R ≃[ring] S
⊢ ∀ (x y : R), Equiv.toFun f.toEquiv (x + y) = Equiv.toFun f.toEquiv x + Equiv.toFun f.toEquiv y

Next tactic:
intro x y