import VersoManual
import Manual.Meta
-- Minimal-Imports statt `import Mathlib`, ermittelt mit
-- `#min_imports`.
import Mathlib.Data.Nat.Prime.Int
import Mathlib.RingTheory.Polynomial.Eisenstein.Criterion

open Verso.Genre
open Verso.Genre.Manual.InlineLean

set_option pp.rawOnError true
set_option verso.docstring.allowMissing true

#doc (Manual) "Polynome und Irreduzibilität" =>
%%%
htmlSplit := .never
tag := "polynome"
file := "polynome"
%%%

Dieses Kapitel übersetzt die beiden Beispiele nach dem
Eisenstein-Kriterium aus Kapitel 7 des Skripts nach Lean; das
Kriterium selbst zitieren wir aus Mathlib.  Nebenbei lernen wir die
Polynom-API kennen.

# Das Mathlib-Wörterbuch

* Der Polynomring über `R` heißt `Polynomial R`, mit der Notation
  `R[X]`.  Die Variable ist `X`, das konstante Polynom zu `a : R` ist
  `C a`; ein Polynom wie `x³−2` schreibt sich also `X ^ 3 - C 2`.

* Der k-te Koeffizient ist `f.coeff k`, der Grad `f.degree`.
  Achtung: `degree` hat Werte in `WithBot ℕ` — das Nullpolynom
  bekommt den Grad `⊥` („minus unendlich“, wie im Skript).  Daneben
  gibt es `f.natDegree : ℕ`.

* „f ist normiert“ (Leitkoeffizient 1) ist `f.Monic`; „f ist
  irreduzibel“ ist `Irreducible f`; die Bedingung „ggT der
  Koeffizienten ist 1“ aus dem Eisenstein-Kriterium heißt
  `f.IsPrimitive` (kein Nichteinheits-Teiler in `R`).

# Das Eisenstein-Kriterium

Satz 7.2.1 des Skripts:

> *Satz 7.2.1 (Eisenstein-Kriterium).* Es sei $`R` ein faktorieller
  Ring und es sei
  $`f = a_0 + a_1 \cdot x + \dots + a_n \cdot x^n \in R[x]` ein
  Polynom vom Grad $`n > 0`.  Weiter sei
  $`\operatorname{ggT}(a_0, \dots, a_n) = 1`.  Wenn es ein
  Primelement $`p \in R` gibt mit $`p \mid a_0`, $`p \mid a_1`, …,
  $`p \mid a_{n-1}` und $`p^2 \nmid a_0`, dann ist $`f` irreduzibel
  in $`R[x]`.

In Mathlib heißt der Satz
`Polynomial.irreducible_of_eisenstein_criterion`.  Er ist dort über
ein Primideal `P` statt eines Primelements $`p` formuliert — für uns
ist `P` das Hauptideal $`(p)` aus dem letzten Kapitel, und „$`p`
teilt $`a_k`“ wird zu `f.coeff k ∈ Ideal.span {p}`.  Statt
„$`p \nmid a_n`“ (was im Skript aus $`\operatorname{ggT} = 1` folgt)
verlangt Mathlib direkt `f.leadingCoeff ∉ P`.

# Erstes Beispiel: xⁿ − r

> Das Polynom $`x^n - r \in \mathbb{Z}[x]` ist irreduzibel, wenn
  $`r` durch eine Primzahl $`p`, aber nicht durch $`p^2` teilbar
  ist.

Das Skript lässt die Kontrolle der Eisenstein-Bedingungen als
Kopfrechnung weg — in Lean führen wir sie aus und lernen dabei die
Koeffizienten-API kennen: `coeff_sub`, `coeff_X_pow` und `coeff_C`
berechnen die Koeffizienten von $`x^n - r`, nämlich $`a_n = 1`,
$`a_0 = -r` und $`a_k = 0` sonst.

```lean
open Polynomial

theorem xn_sub_r_irreduzibel (n : ℕ) (hn : 0 < n) (r : ℤ)
    (p : ℕ) (hp : p.Prime) (hpr : (p : ℤ) ∣ r)
    (hp2r : ¬ (p : ℤ) ^ 2 ∣ r) :
    Irreducible (X ^ n - C r) := by
  -- Das Primelement p des Skripts wird zum Primideal (p):
  have hprime : Prime (p : ℤ) :=
    Nat.prime_iff_prime_int.mp hp
  have hP : (Ideal.span {(p : ℤ)}).IsPrime :=
    (Ideal.span_singleton_prime hprime.ne_zero).mpr hprime
  -- Grad und Leitkoeffizient von f = xⁿ − r:
  have hmonic : (X ^ n - C r).Monic :=
    monic_X_pow_sub_C r hn.ne'
  have hdeg := degree_X_pow_sub_C hn r
  apply irreducible_of_eisenstein_criterion hP
  -- „p ∤ aₙ“: Der Leitkoeffizient ist 1, und p ∤ 1, weil
  -- p keine Einheit ist.
  · rw [hmonic.leadingCoeff, Ideal.mem_span_singleton]
    exact fun h => hprime.not_isUnit (isUnit_of_dvd_one h)
  -- „p|a₀, …, p|a_{n−1}“: Unterhalb von Grad n sind die
  -- Koeffizienten −r (bei k = 0) und 0 (sonst) — beide
  -- durch p teilbar.
  · intro k hk
    have hkn : k < n := by
      rw [hdeg] at hk
      exact_mod_cast hk
    rw [coeff_sub, coeff_X_pow, if_neg hkn.ne, coeff_C,
      Ideal.mem_span_singleton]
    rcases eq_or_ne k 0 with h0 | h0
    · subst h0
      simpa using hpr
    · simp [h0]
  -- „… vom Grad n > 0.“
  · rw [hdeg]
    exact_mod_cast hn
  -- „p² ∤ a₀“: Der konstante Koeffizient ist −r.
  · rw [Ideal.span_singleton_pow, Ideal.mem_span_singleton,
      coeff_sub, coeff_X_pow, if_neg hn.ne, coeff_C,
      if_pos rfl, zero_sub, dvd_neg]
    exact hp2r
  -- „ggT(a₀, …, aₙ) = 1“: f ist normiert, also primitiv.
  · exact hmonic.isPrimitive
```

# Bemerkungen

Mathlibs Beweis des Eisenstein-Kriteriums folgt derselben Idee wie
das Erklärvideo 9-1 des Skripts: Reduktion der Koeffizienten modulo
`p`.  Auch das Gauß-Kriterium aus dem ersten Teil des Kapitels steht
in Mathlib (Datei `Mathlib.RingTheory.Polynomial.GaussLemma`).  Das
zweite Beispiel des Skripts — `xⁿ − p` ist irreduzibel und deshalb
das Minimalpolynom von `ⁿ√p` — greifen wir im Kapitel über
Körpererweiterungen wieder auf.

# Übungsaufgabe

Genau dieses zweite Beispiel ist die Übung:

> Das Polynom $`x^n - p \in \mathbb{Z}[x]` ist für jede Primzahl
  $`p` irreduzibel.

Wenden Sie `xn_sub_r_irreduzibel` mit `r = p` an.  Zu zeigen bleibt
$`p^2 \nmid p`: Aus $`p = p^2 \cdot c` folgt durch Kürzen
$`1 = p \cdot c` — dann wäre $`p` eine Einheit, im Widerspruch zur
Primalität.  Nützlich sind
`mul_left_cancel₀`, `isUnit_of_dvd_one` und `Prime.not_isUnit`.
Öffnen Sie `AlgebraInLean/Polynomials.lean` und ersetzen Sie das
`sorry` durch einen Beweis.

```lean
theorem xn_sub_p_irreduzibel (n : ℕ) (hn : 0 < n) (p : ℕ)
    (hp : p.Prime) :
    Irreducible (X ^ n - C (p : ℤ)) := by
  sorry
```
