import TestGame.Metadata

import Mathlib.Data.Real.Basic           -- definiert `ℝ`
import Mathlib.Algebra.Module.LinearMap -- definiert `→ₗ`
import Mathlib.Tactic.FinCases
import Mathlib.Data.Fin.VecNotation

Game "TestGame"
World "Basis"
Level 1

notation "ℝ²" => Fin 2 → ℝ

Title "Lineare Abbildung"

Introduction
"
Sei `R` ein Ring und `V W` zwei `R`-Moduln. Eine `R`-lineare Abbildung wird in Lean
folgendermassen geschrieben: `V →ₗ[R] W` (`\\to` + `\\_l`).

Man erstellt eine lineare Abbildung aus einer Funktion `f : V → W` zusammen mit den beweisen,
dass `f` Addition und Skalarmultiplikation erhält,
i.e. `f (x + y) = f x + f y` und `f (r • x) = r • f x`.

Hier definieren wir zum Beispiel die Null-Abbildung, die einfach alles auf `0` sendet:

```
variables {R V W : Type*} [ring R] [add_comm_monoid V] [add_comm_monoid W]
[module R V] [module R W]

def my_zero_map : V →ₗ[R] W :=
  { to_fun := λ x, 0,
    map_add' :=
    begin
      intros,
      simp,
    end,
    map_smul' :=
    begin
      intros,
      simp,
    end }
```

"

Statement
"
Zeige dass die Abbildung

```
  ℝ² → ℝ²
  (x, y) ↦ (5x + 2y, x - y)
```

`ℝ`-linear ist.
"
    : ℝ² →ₗ[ℝ] ℝ² :=
  { toFun := fun v ↦ ![5 * (v 1) + 2 * (v 2), (v 1) - (v 2)]
    map_add' := by
      -- Wähle zwei beliebige Vektoren mit `intros` aus.
      intro x y
      -- Das Lemma `funext` sagt das zwei Funktionen identisch sind, wenn sie für jeden Wert ereinstimmen:
      -- `(∀ i, f i = g i) → f = g`. Da Vektoren einfach als Funktionen von einem Indexset codiert sind,
      -- kannst du mit `apply funext` komponentenweise rechnen.
      funext i
      -- Mit `fin_cases i` kannst du pro möglichem Wert von `i` ein Goal auftun. D.h. im ersten gilt dann
      -- `i = 0`, im zweiten Goal `i = 1`.
      fin_cases i
      -- Dies ist der Fall `i = 0`.
        -- Das Goal hat jetzt Terme der Form `![a, b] 0`, und du weisst was das sein sollte, nämlich
        -- einfach der erste Komponent `a`. Die Taktik `simp` ist für solche Vereinfachungnen gedacht.
      · simp
        -- Einfache Rechenaufgaben hast du ja bereits gemacht.
        -- `ring` oder `linarith` machen dies automatisch für dich.
        ring
      -- Und jetzt noch den Fall `i = 1`.
      · simp
        ring
    map_smul' := by
      intro r x
      funext i
      fin_cases i
        -- Bemerkung: Wenn du jetzt `simp` brauchst, macht es sogar noch mehr als vorher.
        -- Skalarmultiplikation ist einfach als komponentenweise Multiplikation definiert.
        -- Entsprechend braucht `simp` ein Lemma `smul_eq_mul : a • b = a * b`.
      · simp
        ring
      · simp
        ring
  }
