l3lab/ntp-mathlib huggingface dataset:
/-- There is a primitive additive character on the finite field `F` if the characteristic
of the target is different from that of `F`.
We obtain it as the composition of the trace from `F` to `ZMod p` with a primitive
additive character on `ZMod p`, where `p` is the characteristic of `F`. -/
noncomputable def primitiveCharFiniteField (F F' : Type*) [Field F] [Fintype F] [Field F']
    (h : ringChar F' ≠ ringChar F) : PrimitiveAddChar F F' := by
  let p := ringChar F
  haveI hp : Fact p.Prime := ⟨CharP.char_is_prime F _⟩
  let pp := p.toPNat hp.1.pos
  have hp₂ : ¬ringChar F' ∣ p := by
    cases' CharP.char_is_prime_or_zero F' (ringChar F') with hq hq
    · exact mt (Nat.Prime.dvd_iff_eq hp.1 (Nat.Prime.ne_one hq)).mp h.symm
    · rw [hq]
      exact fun hf => Nat.Prime.ne_zero hp.1 (zero_dvd_iff.mp hf)
  let ψ := primitiveZModChar pp F' (neZero_iff.mp (NeZero.of_not_dvd F' hp₂))
  letI : Algebra (ZMod p) F := ZMod.algebra _ _
  let ψ' := ψ.char.comp (AddMonoidHom.toMultiplicative (Algebra.trace (ZMod p) F).toAddMonoidHom)
  have hψ' : IsNontrivial ψ' := by
    obtain ⟨a, ha⟩ := FiniteField.trace_to_zmod_nondegenerate F one_ne_zero
    rw [one_mul] at ha
    exact ⟨a, fun hf => ha <| (ψ.prim.zmod_char_eq_one_iff pp <| Algebra.trace (ZMod p) F a).mp hf⟩
  

Proof state:
R : Type u
inst✝⁵ : CommRing R
R' : Type v
inst✝⁴ : CommRing R'
C : Type v
inst✝³ : CommRing C
F : Type u_1
F' : Type u_2
inst✝² : Field F
inst✝¹ : Fintype F
inst✝ : Field F'
h : ringChar F' ≠ ringChar F
p : ℕ := ringChar F
hp : Fact (Nat.Prime p)
pp : ℕ+ := Nat.toPNat p
hp₂ : ¬ringChar F' ∣ p
ψ : PrimitiveAddChar (ZMod ↑pp) F' := primitiveZModChar pp F' (_ : ↑↑pp ≠ 0)
this : Algebra (ZMod p) F := ZMod.algebra F p
ψ' : Multiplicative F →* CyclotomicField (PrimitiveAddChar.n ψ) F' :=
  MonoidHom.comp (PrimitiveAddChar.char ψ)
    (AddMonoidHom.toMultiplicative (LinearMap.toAddMonoidHom (Algebra.trace (ZMod p) F)))
hψ' : IsNontrivial ψ'
⊢ PrimitiveAddChar F F'

Next tactic:
exact ⟨ψ.n, ψ', hψ'.isPrimitive⟩
/-- The sum over the values of a nontrivial additive character vanishes if the target ring
is a domain. -/
theorem sum_eq_zero_of_isNontrivial [IsDomain R'] {ψ : AddChar R R'} (hψ : IsNontrivial ψ) :
    ∑ a, ψ a = 0 := by
  

Proof state:
R : Type u
inst✝⁴ : CommRing R
R' : Type v
inst✝³ : CommRing R'
C : Type v
inst✝² : CommRing C
inst✝¹ : Fintype R
inst✝ : IsDomain R'
ψ : AddChar R R'
hψ : IsNontrivial ψ
⊢ ∑ a : R, ψ a = 0

Next tactic:
rcases hψ with ⟨b, hb⟩
/-- The sum over the values of a nontrivial additive character vanishes if the target ring
is a domain. -/
theorem sum_eq_zero_of_isNontrivial [IsDomain R'] {ψ : AddChar R R'} (hψ : IsNontrivial ψ) :
    ∑ a, ψ a = 0 := by
  rcases hψ with ⟨b, hb⟩
  

Proof state:
case intro
R : Type u
inst✝⁴ : CommRing R
R' : Type v
inst✝³ : CommRing R'
C : Type v
inst✝² : CommRing C
inst✝¹ : Fintype R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hb : ψ b ≠ 1
⊢ ∑ a : R, ψ a = 0

Next tactic:
have h₁ : ∑ a : R, ψ (b + a) = ∑ a : R, ψ a :=
    Fintype.sum_bijective _ (AddGroup.addLeft_bijective b) _ _ fun x => rfl
/-- The sum over the values of a nontrivial additive character vanishes if the target ring
is a domain. -/
theorem sum_eq_zero_of_isNontrivial [IsDomain R'] {ψ : AddChar R R'} (hψ : IsNontrivial ψ) :
    ∑ a, ψ a = 0 := by
  rcases hψ with ⟨b, hb⟩
  have h₁ : ∑ a : R, ψ (b + a) = ∑ a : R, ψ a :=
    Fintype.sum_bijective _ (AddGroup.addLeft_bijective b) _ _ fun x => rfl
  

Proof state:
case intro
R : Type u
inst✝⁴ : CommRing R
R' : Type v
inst✝³ : CommRing R'
C : Type v
inst✝² : CommRing C
inst✝¹ : Fintype R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hb : ψ b ≠ 1
h₁ : ∑ a : R, ψ (b + a) = ∑ a : R, ψ a
⊢ ∑ a : R, ψ a = 0

Next tactic:
simp_rw [map_add_mul] at h₁
/-- The sum over the values of a nontrivial additive character vanishes if the target ring
is a domain. -/
theorem sum_eq_zero_of_isNontrivial [IsDomain R'] {ψ : AddChar R R'} (hψ : IsNontrivial ψ) :
    ∑ a, ψ a = 0 := by
  rcases hψ with ⟨b, hb⟩
  have h₁ : ∑ a : R, ψ (b + a) = ∑ a : R, ψ a :=
    Fintype.sum_bijective _ (AddGroup.addLeft_bijective b) _ _ fun x => rfl
  simp_rw [map_add_mul] at h₁
  

Proof state:
case intro
R : Type u
inst✝⁴ : CommRing R
R' : Type v
inst✝³ : CommRing R'
C : Type v
inst✝² : CommRing C
inst✝¹ : Fintype R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hb : ψ b ≠ 1
h₁ : ∑ x : R, ψ b * ψ x = ∑ a : R, ψ a
⊢ ∑ a : R, ψ a = 0

Next tactic:
have h₂ : ∑ a : R, ψ a = Finset.univ.sum ↑ψ := rfl
/-- The sum over the values of a nontrivial additive character vanishes if the target ring
is a domain. -/
theorem sum_eq_zero_of_isNontrivial [IsDomain R'] {ψ : AddChar R R'} (hψ : IsNontrivial ψ) :
    ∑ a, ψ a = 0 := by
  rcases hψ with ⟨b, hb⟩
  have h₁ : ∑ a : R, ψ (b + a) = ∑ a : R, ψ a :=
    Fintype.sum_bijective _ (AddGroup.addLeft_bijective b) _ _ fun x => rfl
  simp_rw [map_add_mul] at h₁
  have h₂ : ∑ a : R, ψ a = Finset.univ.sum ↑ψ := rfl
  

Proof state:
case intro
R : Type u
inst✝⁴ : CommRing R
R' : Type v
inst✝³ : CommRing R'
C : Type v
inst✝² : CommRing C
inst✝¹ : Fintype R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hb : ψ b ≠ 1
h₁ : ∑ x : R, ψ b * ψ x = ∑ a : R, ψ a
h₂ : ∑ a : R, ψ a = Finset.sum Finset.univ ⇑ψ
⊢ ∑ a : R, ψ a = 0

Next tactic:
rw [← Finset.mul_sum, h₂] at h₁
/-- The sum over the values of a nontrivial additive character vanishes if the target ring
is a domain. -/
theorem sum_eq_zero_of_isNontrivial [IsDomain R'] {ψ : AddChar R R'} (hψ : IsNontrivial ψ) :
    ∑ a, ψ a = 0 := by
  rcases hψ with ⟨b, hb⟩
  have h₁ : ∑ a : R, ψ (b + a) = ∑ a : R, ψ a :=
    Fintype.sum_bijective _ (AddGroup.addLeft_bijective b) _ _ fun x => rfl
  simp_rw [map_add_mul] at h₁
  have h₂ : ∑ a : R, ψ a = Finset.univ.sum ↑ψ := rfl
  rw [← Finset.mul_sum, h₂] at h₁
  

Proof state:
case intro
R : Type u
inst✝⁴ : CommRing R
R' : Type v
inst✝³ : CommRing R'
C : Type v
inst✝² : CommRing C
inst✝¹ : Fintype R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hb : ψ b ≠ 1
h₁ : ψ b * Finset.sum Finset.univ ⇑ψ = Finset.sum Finset.univ ⇑ψ
h₂ : ∑ a : R, ψ a = Finset.sum Finset.univ ⇑ψ
⊢ ∑ a : R, ψ a = 0

Next tactic:
exact eq_zero_of_mul_eq_self_left hb h₁
/-- The sum over the values of the trivial additive character is the cardinality of the source. -/
theorem sum_eq_card_of_is_trivial {ψ : AddChar R R'} (hψ : ¬IsNontrivial ψ) :
    ∑ a, ψ a = Fintype.card R := by
  

Proof state:
R : Type u
inst✝³ : CommRing R
R' : Type v
inst✝² : CommRing R'
C : Type v
inst✝¹ : CommRing C
inst✝ : Fintype R
ψ : AddChar R R'
hψ : ¬IsNontrivial ψ
⊢ ∑ a : R, ψ a = ↑(Fintype.card R)

Next tactic:
simp only [IsNontrivial] at hψ
/-- The sum over the values of the trivial additive character is the cardinality of the source. -/
theorem sum_eq_card_of_is_trivial {ψ : AddChar R R'} (hψ : ¬IsNontrivial ψ) :
    ∑ a, ψ a = Fintype.card R := by
  simp only [IsNontrivial] at hψ
  

Proof state:
R : Type u
inst✝³ : CommRing R
R' : Type v
inst✝² : CommRing R'
C : Type v
inst✝¹ : CommRing C
inst✝ : Fintype R
ψ : AddChar R R'
hψ : ¬∃ a, ψ a ≠ 1
⊢ ∑ a : R, ψ a = ↑(Fintype.card R)

Next tactic:
push_neg at hψ
/-- The sum over the values of the trivial additive character is the cardinality of the source. -/
theorem sum_eq_card_of_is_trivial {ψ : AddChar R R'} (hψ : ¬IsNontrivial ψ) :
    ∑ a, ψ a = Fintype.card R := by
  simp only [IsNontrivial] at hψ
  push_neg at hψ
  

Proof state:
R : Type u
inst✝³ : CommRing R
R' : Type v
inst✝² : CommRing R'
C : Type v
inst✝¹ : CommRing C
inst✝ : Fintype R
ψ : AddChar R R'
hψ : ∀ (a : R), ψ a = 1
⊢ ∑ a : R, ψ a = ↑(Fintype.card R)

Next tactic:
simp only [hψ, Finset.sum_const, Nat.smul_one_eq_coe]
/-- The sum over the values of the trivial additive character is the cardinality of the source. -/
theorem sum_eq_card_of_is_trivial {ψ : AddChar R R'} (hψ : ¬IsNontrivial ψ) :
    ∑ a, ψ a = Fintype.card R := by
  simp only [IsNontrivial] at hψ
  push_neg at hψ
  simp only [hψ, Finset.sum_const, Nat.smul_one_eq_coe]
  

Proof state:
R : Type u
inst✝³ : CommRing R
R' : Type v
inst✝² : CommRing R'
C : Type v
inst✝¹ : CommRing C
inst✝ : Fintype R
ψ : AddChar R R'
hψ : ∀ (a : R), ψ a = 1
⊢ ↑(Finset.card Finset.univ) = ↑(Fintype.card R)

Next tactic:
rfl
/-- The sum over the values of `mulShift ψ b` for `ψ` primitive is zero when `b ≠ 0`
and `#R` otherwise. -/
theorem sum_mulShift [DecidableEq R] [IsDomain R'] {ψ : AddChar R R'} (b : R)
    (hψ : IsPrimitive ψ) : ∑ x : R, ψ (x * b) = if b = 0 then Fintype.card R else 0 := by
  

Proof state:
R : Type u
inst✝⁵ : CommRing R
R' : Type v
inst✝⁴ : CommRing R'
C : Type v
inst✝³ : CommRing C
inst✝² : Fintype R
inst✝¹ : DecidableEq R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hψ : IsPrimitive ψ
⊢ ∑ x : R, ψ (x * b) = ↑(if b = 0 then Fintype.card R else 0)

Next tactic:
split_ifs with h
/-- The sum over the values of `mulShift ψ b` for `ψ` primitive is zero when `b ≠ 0`
and `#R` otherwise. -/
theorem sum_mulShift [DecidableEq R] [IsDomain R'] {ψ : AddChar R R'} (b : R)
    (hψ : IsPrimitive ψ) : ∑ x : R, ψ (x * b) = if b = 0 then Fintype.card R else 0 := by
  split_ifs with h
  · -- case `b = 0`
    

Proof state:
case pos
R : Type u
inst✝⁵ : CommRing R
R' : Type v
inst✝⁴ : CommRing R'
C : Type v
inst✝³ : CommRing C
inst✝² : Fintype R
inst✝¹ : DecidableEq R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hψ : IsPrimitive ψ
h : b = 0
⊢ ∑ x : R, ψ (x * b) = ↑(Fintype.card R)

Next tactic:
simp only [h, mul_zero, map_zero_one, Finset.sum_const, Nat.smul_one_eq_coe]
/-- The sum over the values of `mulShift ψ b` for `ψ` primitive is zero when `b ≠ 0`
and `#R` otherwise. -/
theorem sum_mulShift [DecidableEq R] [IsDomain R'] {ψ : AddChar R R'} (b : R)
    (hψ : IsPrimitive ψ) : ∑ x : R, ψ (x * b) = if b = 0 then Fintype.card R else 0 := by
  split_ifs with h
  · -- case `b = 0`
    simp only [h, mul_zero, map_zero_one, Finset.sum_const, Nat.smul_one_eq_coe]
    

Proof state:
case pos
R : Type u
inst✝⁵ : CommRing R
R' : Type v
inst✝⁴ : CommRing R'
C : Type v
inst✝³ : CommRing C
inst✝² : Fintype R
inst✝¹ : DecidableEq R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hψ : IsPrimitive ψ
h : b = 0
⊢ ↑(Finset.card Finset.univ) = ↑(Fintype.card R)

Next tactic:
rfl
/-- The sum over the values of `mulShift ψ b` for `ψ` primitive is zero when `b ≠ 0`
and `#R` otherwise. -/
theorem sum_mulShift [DecidableEq R] [IsDomain R'] {ψ : AddChar R R'} (b : R)
    (hψ : IsPrimitive ψ) : ∑ x : R, ψ (x * b) = if b = 0 then Fintype.card R else 0 := by
  split_ifs with h
  · -- case `b = 0`
    simp only [h, mul_zero, map_zero_one, Finset.sum_const, Nat.smul_one_eq_coe]
    rfl
  · -- case `b ≠ 0`
    

Proof state:
case neg
R : Type u
inst✝⁵ : CommRing R
R' : Type v
inst✝⁴ : CommRing R'
C : Type v
inst✝³ : CommRing C
inst✝² : Fintype R
inst✝¹ : DecidableEq R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hψ : IsPrimitive ψ
h : ¬b = 0
⊢ ∑ x : R, ψ (x * b) = ↑0

Next tactic:
simp_rw [mul_comm]
/-- The sum over the values of `mulShift ψ b` for `ψ` primitive is zero when `b ≠ 0`
and `#R` otherwise. -/
theorem sum_mulShift [DecidableEq R] [IsDomain R'] {ψ : AddChar R R'} (b : R)
    (hψ : IsPrimitive ψ) : ∑ x : R, ψ (x * b) = if b = 0 then Fintype.card R else 0 := by
  split_ifs with h
  · -- case `b = 0`
    simp only [h, mul_zero, map_zero_one, Finset.sum_const, Nat.smul_one_eq_coe]
    rfl
  · -- case `b ≠ 0`
    simp_rw [mul_comm]
    

Proof state:
case neg
R : Type u
inst✝⁵ : CommRing R
R' : Type v
inst✝⁴ : CommRing R'
C : Type v
inst✝³ : CommRing C
inst✝² : Fintype R
inst✝¹ : DecidableEq R
inst✝ : IsDomain R'
ψ : AddChar R R'
b : R
hψ : IsPrimitive ψ
h : ¬b = 0
⊢ ∑ x : R, ψ (b * x) = ↑0

Next tactic:
exact mod_cast sum_eq_zero_of_isNontrivial (hψ b h)
@[simp]
theorem mul_inv_cancel_right₀ (h : b ≠ 0) (a : G₀) : a * b * b⁻¹ = a :=
  calc
    a * b * b⁻¹ = a * (b * b⁻¹) := mul_assoc _ _ _
    _ = a := by 

Proof state:
G₀ : Type u
M₀ : Type u_1
M₀' : Type u_2
G₀' : Type u_3
inst✝ : GroupWithZero G₀
a✝ b c g h✝ x : G₀
h : b ≠ 0
a : G₀
⊢ a * (b * b⁻¹) = a

Next tactic:
simp [h]
@[simp]
theorem mul_inv_cancel_left₀ (h : a ≠ 0) (b : G₀) : a * (a⁻¹ * b) = b :=
  calc
    a * (a⁻¹ * b) = a * a⁻¹ * b := (mul_assoc _ _ _).symm
    _ = b := by 

Proof state:
G₀ : Type u
M₀ : Type u_1
M₀' : Type u_2
G₀' : Type u_3
inst✝ : GroupWithZero G₀
a b✝ c g h✝ x : G₀
h : a ≠ 0
b : G₀
⊢ a * a⁻¹ * b = b

Next tactic:
simp [h]
/-- If `α` has no zero divisors, then the product of two elements equals zero iff one of them
equals zero. -/
@[simp]
theorem zero_eq_mul : 0 = a * b ↔ a = 0 ∨ b = 0 := by 

Proof state:
G₀ : Type u
M₀ : Type u_1
M₀' : Type u_2
G₀' : Type u_3
inst✝¹ : MulZeroClass M₀
inst✝ : NoZeroDivisors M₀
a b : M₀
⊢ 0 = a * b ↔ a = 0 ∨ b = 0

Next tactic:
rw [eq_comm, mul_eq_zero]
theorem mul_self_eq_zero : a * a = 0 ↔ a = 0 := by 

Proof state:
G₀ : Type u
M₀ : Type u_1
M₀' : Type u_2
G₀' : Type u_3
inst✝¹ : MulZeroClass M₀
inst✝ : NoZeroDivisors M₀
a b : M₀
⊢ a * a = 0 ↔ a = 0

Next tactic:
simp
theorem zero_eq_mul_self : 0 = a * a ↔ a = 0 := by 

Proof state:
G₀ : Type u
M₀ : Type u_1
M₀' : Type u_2
G₀' : Type u_3
inst✝¹ : MulZeroClass M₀
inst✝ : NoZeroDivisors M₀
a b : M₀
⊢ 0 = a * a ↔ a = 0

Next tactic:
simp
theorem mem_adjoin_iff (x : E) :
    x ∈ adjoin F S ↔ ∃ r s : MvPolynomial S F,
      x = MvPolynomial.aeval Subtype.val r / MvPolynomial.aeval Subtype.val s := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
x : E
⊢ x ∈ adjoin F S ↔ ∃ r s, x = (MvPolynomial.aeval Subtype.val) r / (MvPolynomial.aeval Subtype.val) s

Next tactic:
simp only [adjoin, mem_mk, Subring.mem_toSubsemiring, Subfield.mem_toSubring,
    Subfield.mem_closure_iff, ← Algebra.adjoin_eq_ring_closure, Subalgebra.mem_toSubring,
    Algebra.adjoin_eq_range, AlgHom.mem_range, exists_exists_eq_and]
theorem mem_adjoin_iff (x : E) :
    x ∈ adjoin F S ↔ ∃ r s : MvPolynomial S F,
      x = MvPolynomial.aeval Subtype.val r / MvPolynomial.aeval Subtype.val s := by
  simp only [adjoin, mem_mk, Subring.mem_toSubsemiring, Subfield.mem_toSubring,
    Subfield.mem_closure_iff, ← Algebra.adjoin_eq_ring_closure, Subalgebra.mem_toSubring,
    Algebra.adjoin_eq_range, AlgHom.mem_range, exists_exists_eq_and]
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
x : E
⊢ (∃ a a_1, (MvPolynomial.aeval Subtype.val) a / (MvPolynomial.aeval Subtype.val) a_1 = x) ↔
    ∃ r s, x = (MvPolynomial.aeval Subtype.val) r / (MvPolynomial.aeval Subtype.val) s

Next tactic:
tauto
theorem mem_adjoin_simple_iff {α : E} (x : E) :
    x ∈ adjoin F {α} ↔ ∃ r s : F[X], x = aeval α r / aeval α s := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
α x : E
⊢ x ∈ adjoin F {α} ↔ ∃ r s, x = (aeval α) r / (aeval α) s

Next tactic:
simp only [adjoin, mem_mk, Subring.mem_toSubsemiring, Subfield.mem_toSubring,
    Subfield.mem_closure_iff, ← Algebra.adjoin_eq_ring_closure, Subalgebra.mem_toSubring,
    Algebra.adjoin_singleton_eq_range_aeval, AlgHom.mem_range, exists_exists_eq_and]
theorem mem_adjoin_simple_iff {α : E} (x : E) :
    x ∈ adjoin F {α} ↔ ∃ r s : F[X], x = aeval α r / aeval α s := by
  simp only [adjoin, mem_mk, Subring.mem_toSubsemiring, Subfield.mem_toSubring,
    Subfield.mem_closure_iff, ← Algebra.adjoin_eq_ring_closure, Subalgebra.mem_toSubring,
    Algebra.adjoin_singleton_eq_range_aeval, AlgHom.mem_range, exists_exists_eq_and]
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
α x : E
⊢ (∃ a a_1, (aeval α) a / (aeval α) a_1 = x) ↔ ∃ r s, x = (aeval α) r / (aeval α) s

Next tactic:
tauto
instance : CompleteLattice (IntermediateField F E) where
  __ := GaloisInsertion.liftCompleteLattice IntermediateField.gi
  bot :=
    { toSubalgebra := ⊥
      inv_mem' := by 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
src✝ : CompleteLattice (IntermediateField F E) := GaloisInsertion.liftCompleteLattice gi
⊢ ∀ x ∈ ⊥.carrier, x⁻¹ ∈ ⊥.carrier

Next tactic:
rintro x ⟨r, rfl⟩
instance : CompleteLattice (IntermediateField F E) where
  __ := GaloisInsertion.liftCompleteLattice IntermediateField.gi
  bot :=
    { toSubalgebra := ⊥
      inv_mem' := by rintro x ⟨r, rfl⟩; 

Proof state:
case intro
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
src✝ : CompleteLattice (IntermediateField F E) := GaloisInsertion.liftCompleteLattice gi
r : F
⊢ (↑(Algebra.ofId F E) r)⁻¹ ∈ ⊥.carrier

Next tactic:
exact ⟨r⁻¹, map_inv₀ _ _⟩
@[simp]
theorem sInf_toSubalgebra (S : Set (IntermediateField F E)) :
    (sInf S).toSubalgebra = sInf (toSubalgebra '' S) :=
  SetLike.coe_injective <| by 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set (IntermediateField F E)
⊢ ↑(sInf S).toSubalgebra = ↑(sInf (toSubalgebra '' S))

Next tactic:
simp [Set.sUnion_image]
@[simp]
theorem sInf_toSubfield (S : Set (IntermediateField F E)) :
    (sInf S).toSubfield = sInf (toSubfield '' S) :=
  SetLike.coe_injective <| by 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set (IntermediateField F E)
⊢ ↑(toSubfield (sInf S)) = ↑(sInf (toSubfield '' S))

Next tactic:
simp [Set.sUnion_image]
@[simp, norm_cast]
theorem coe_iInf {ι : Sort*} (S : ι → IntermediateField F E) : (↑(iInf S) : Set E) = ⋂ i, S i := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
ι : Sort u_3
S : ι → IntermediateField F E
⊢ ↑(iInf S) = ⋂ i, ↑(S i)

Next tactic:
simp [iInf]
@[simp]
theorem iInf_toSubalgebra {ι : Sort*} (S : ι → IntermediateField F E) :
    (iInf S).toSubalgebra = ⨅ i, (S i).toSubalgebra :=
  SetLike.coe_injective <| by 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
ι : Sort u_3
S : ι → IntermediateField F E
⊢ ↑(iInf S).toSubalgebra = ↑(⨅ i, (S i).toSubalgebra)

Next tactic:
simp [iInf]
@[simp]
theorem iInf_toSubfield {ι : Sort*} (S : ι → IntermediateField F E) :
    (iInf S).toSubfield = ⨅ i, (S i).toSubfield :=
  SetLike.coe_injective <| by 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
ι : Sort u_3
S : ι → IntermediateField F E
⊢ ↑(toSubfield (iInf S)) = ↑(⨅ i, toSubfield (S i))

Next tactic:
simp [iInf]
@[simp]
theorem equivOfEq_rfl (S : IntermediateField F E) : equivOfEq (rfl : S = S) = AlgEquiv.refl := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : IntermediateField F E
⊢ equivOfEq (_ : S = S) = AlgEquiv.refl

Next tactic:
ext
@[simp]
theorem equivOfEq_rfl (S : IntermediateField F E) : equivOfEq (rfl : S = S) = AlgEquiv.refl := by
  ext; 

Proof state:
case h.a
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : IntermediateField F E
a✝ : ↥S
⊢ ↑((equivOfEq (_ : S = S)) a✝) = ↑(AlgEquiv.refl a✝)

Next tactic:
rfl
theorem botEquiv_def (x : F) : botEquiv F E (algebraMap F (⊥ : IntermediateField F E) x) = x :=
  by 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
x : F
⊢ (botEquiv F E) ((algebraMap F ↥⊥) x) = x

Next tactic:
simp
instance isScalarTower_over_bot : IsScalarTower (⊥ : IntermediateField F E) F E :=
  IsScalarTower.of_algebraMap_eq
    (by
      

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
⊢ ∀ (x : ↥⊥), (algebraMap (↥⊥) E) x = (algebraMap F E) ((algebraMap (↥⊥) F) x)

Next tactic:
intro x
instance isScalarTower_over_bot : IsScalarTower (⊥ : IntermediateField F E) F E :=
  IsScalarTower.of_algebraMap_eq
    (by
      intro x
      

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
x : ↥⊥
⊢ (algebraMap (↥⊥) E) x = (algebraMap F E) ((algebraMap (↥⊥) F) x)

Next tactic:
obtain ⟨y, rfl⟩ := (botEquiv F E).symm.surjective x
instance isScalarTower_over_bot : IsScalarTower (⊥ : IntermediateField F E) F E :=
  IsScalarTower.of_algebraMap_eq
    (by
      intro x
      obtain ⟨y, rfl⟩ := (botEquiv F E).symm.surjective x
      

Proof state:
case intro
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
y : F
⊢ (algebraMap (↥⊥) E) ((AlgEquiv.symm (botEquiv F E)) y) =
    (algebraMap F E) ((algebraMap (↥⊥) F) ((AlgEquiv.symm (botEquiv F E)) y))

Next tactic:
rw [coe_algebraMap_over_bot, (botEquiv F E).apply_symm_apply, botEquiv_symm,
        IsScalarTower.algebraMap_apply F (⊥ : IntermediateField F E) E]
theorem adjoin.range_algebraMap_subset : Set.range (algebraMap F E) ⊆ adjoin F S := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
⊢ Set.range ⇑(algebraMap F E) ⊆ ↑(adjoin F S)

Next tactic:
intro x hx
theorem adjoin.range_algebraMap_subset : Set.range (algebraMap F E) ⊆ adjoin F S := by
  intro x hx
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
x : E
hx : x ∈ Set.range ⇑(algebraMap F E)
⊢ x ∈ ↑(adjoin F S)

Next tactic:
cases' hx with f hf
theorem adjoin.range_algebraMap_subset : Set.range (algebraMap F E) ⊆ adjoin F S := by
  intro x hx
  cases' hx with f hf
  

Proof state:
case intro
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
x : E
f : F
hf : (algebraMap F E) f = x
⊢ x ∈ ↑(adjoin F S)

Next tactic:
rw [← hf]
theorem adjoin.range_algebraMap_subset : Set.range (algebraMap F E) ⊆ adjoin F S := by
  intro x hx
  cases' hx with f hf
  rw [← hf]
  

Proof state:
case intro
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
x : E
f : F
hf : (algebraMap F E) f = x
⊢ (algebraMap F E) f ∈ ↑(adjoin F S)

Next tactic:
exact adjoin.algebraMap_mem F S f
/-- If `K` is a field with `F ⊆ K` and `S ⊆ K` then `adjoin F S ≤ K`. -/
theorem adjoin_le_subfield {K : Subfield E} (HF : Set.range (algebraMap F E) ⊆ K) (HS : S ⊆ K) :
    (adjoin F S).toSubfield ≤ K := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
K : Subfield E
HF : Set.range ⇑(algebraMap F E) ⊆ ↑K
HS : S ⊆ ↑K
⊢ toSubfield (adjoin F S) ≤ K

Next tactic:
apply Subfield.closure_le.mpr
/-- If `K` is a field with `F ⊆ K` and `S ⊆ K` then `adjoin F S ≤ K`. -/
theorem adjoin_le_subfield {K : Subfield E} (HF : Set.range (algebraMap F E) ⊆ K) (HS : S ⊆ K) :
    (adjoin F S).toSubfield ≤ K := by
  apply Subfield.closure_le.mpr
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
K : Subfield E
HF : Set.range ⇑(algebraMap F E) ⊆ ↑K
HS : S ⊆ ↑K
⊢ Set.range ⇑(algebraMap F E) ∪ S ⊆ ↑K

Next tactic:
rw [Set.union_subset_iff]
/-- If `K` is a field with `F ⊆ K` and `S ⊆ K` then `adjoin F S ≤ K`. -/
theorem adjoin_le_subfield {K : Subfield E} (HF : Set.range (algebraMap F E) ⊆ K) (HS : S ⊆ K) :
    (adjoin F S).toSubfield ≤ K := by
  apply Subfield.closure_le.mpr
  rw [Set.union_subset_iff]
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S : Set E
K : Subfield E
HF : Set.range ⇑(algebraMap F E) ⊆ ↑K
HS : S ⊆ ↑K
⊢ Set.range ⇑(algebraMap F E) ⊆ ↑K ∧ S ⊆ ↑K

Next tactic:
exact ⟨HF, HS⟩
/-- `F[S][T] = F[S ∪ T]` -/
theorem adjoin_adjoin_left (T : Set E) :
    (adjoin (adjoin F S) T).restrictScalars _ = adjoin F (S ∪ T) := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S T : Set E
⊢ restrictScalars F (adjoin (↥(adjoin F S)) T) = adjoin F (S ∪ T)

Next tactic:
rw [SetLike.ext'_iff]
/-- `F[S][T] = F[S ∪ T]` -/
theorem adjoin_adjoin_left (T : Set E) :
    (adjoin (adjoin F S) T).restrictScalars _ = adjoin F (S ∪ T) := by
  rw [SetLike.ext'_iff]
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S T : Set E
⊢ ↑(restrictScalars F (adjoin (↥(adjoin F S)) T)) = ↑(adjoin F (S ∪ T))

Next tactic:
change (↑(adjoin (adjoin F S) T) : Set E) = _
/-- `F[S][T] = F[S ∪ T]` -/
theorem adjoin_adjoin_left (T : Set E) :
    (adjoin (adjoin F S) T).restrictScalars _ = adjoin F (S ∪ T) := by
  rw [SetLike.ext'_iff]
  change (↑(adjoin (adjoin F S) T) : Set E) = _
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
S T : Set E
⊢ ↑(adjoin (↥(adjoin F S)) T) = ↑(adjoin F (S ∪ T))

Next tactic:
apply Set.eq_of_subset_of_subset