/-- `PreservesOp f opA opB` says that `f : A → B` **preserves the operation**: combining firstand then mapping gives the same as mapping first and then combining,`f (x ∗ y) = f x ⋆ f y` for all `x y`, where `∗` is `opA` and `⋆` is `opB`. -/def PreservesOp {A : Type u} {B : Type v} (f : A → B) (opA : A → A → A) (opB : B → B → B) : Prop := ∀ x y, f (opA x y) = opB (f x) (f y)
preservesOp_idtheoremProved here from basic factsNo axioms
preservesOp_idLean 4Proved here from basic factsFormally verified
/-- The identity map preserves every operation: both sides are `x ∗ y`. -/theorem preservesOp_id {A : Type u} (op : A → A → A) : PreservesOp id op op := fun _ _ => rfl
PreservesOp.comptheoremProved here from basic factsNo axioms
compLean 4Proved here from basic factsFormally verified
/-- **Composites of homomorphisms are homomorphisms.** If `f` turns `∗` into `⋆` and `g` turns`⋆` into `•`, then `g ∘ f` turns `∗` into `•`:`g(f(x ∗ y)) = g(f x ⋆ f y) = g(f x) • g(f y)`. -/theorem PreservesOp.comp {A : Type u} {B : Type v} {C : Type w} {opA : A → A → A} {opB : B → B → B} {opC : C → C → C} {f : A → B} {g : B → C} (hf : PreservesOp f opA opB) (hg : PreservesOp g opB opC) : PreservesOp (g ∘ f) opA opC := by intro x y calc (g ∘ f) (opA x y) = g (f (opA x y)) := rfl _ = g (opB (f x) (f y)) := by rw [hf] _ = opC (g (f x)) (g (f y)) := hg _ _
PreservesOp.inversetheoremProved here from basic factsNo axioms
inverseLean 4Proved here from basic factsFormally verified
/-- **The inverse of a bijective homomorphism is a homomorphism.** Let `g` be a two-sided inverseof `f` (`g (f x) = x` and `f (g u) = u`). For `u v` in `B`, write `u = f (g u)` and`v = f (g v)`; then`g (u ⋆ v) = g (f (g u) ⋆ f (g v)) = g (f (g u ∗ g v)) = g u ∗ g v`.Nothing about groups is used: this holds for any binary operations. -/theorem PreservesOp.inverse {A : Type u} {B : Type v} {opA : A → A → A} {opB : B → B → B} {f : A → B} {g : B → A} (hf : PreservesOp f opA opB) (hgf : Function.LeftInverse g f) (hfg : Function.RightInverse g f) : PreservesOp g opB opA := by intro u v calc g (opB u v) = g (opB (f (g u)) (f (g v))) := by rw [hfg u, hfg v] _ = g (f (opA (g u) (g v))) := by rw [hf] _ = opA (g u) (g v) := hgf _
reduce_addtheoremApplies a library theorempropext, Quot.sound
reduce_addLean 4Applies a library theoremFormally verified
/-- Reduction modulo `n`, `ℤ → ℤ/n`, preserves addition. This is core Mathlib's `Int.cast_add`(the map `ℤ → ZMod n` is the canonical "cast"). -/theorem reduce_add (n : ℕ) : PreservesOp (fun a : ℤ => (a : ZMod n)) (· + ·) (· + ·) := fun a b => Int.cast_add a b
reduce_multheoremApplies a library theorempropext, Quot.sound
reduce_mulLean 4Applies a library theoremFormally verified
/-- Reduction modulo `n` also preserves multiplication: Mathlib's `Int.cast_mul`. -/theorem reduce_mul (n : ℕ) : PreservesOp (fun a : ℤ => (a : ZMod n)) (· * ·) (· * ·) := fun a b => Int.cast_mul a b
reduce_not_injectivetheoremProved here from basic factspropext, Quot.sound
reduce_not_injectiveLean 4Proved here from basic factsFormally verified
/-- …but for `n ≠ 0` it is **not injective**: `n` and `0` have the same remainder. So reductionmod `n` is a homomorphism, not an isomorphism. -/theorem reduce_not_injective (n : ℕ) (hn : n ≠ 0) : ¬ Function.Injective (fun a : ℤ => (a : ZMod n)) := by intro hinj have h : ((n : ℤ) : ZMod n) = ((0 : ℤ) : ZMod n) := by rw [Int.cast_natCast, ZMod.natCast_self, Int.cast_zero] have h' : (n : ℤ) = 0 := hinj h exact hn (by exact_mod_cast h')
map_zero_of_preservesOptheoremProved here from basic factspropext
map_zero_of_preservesOpLean 4Proved here from basic factsFormally verified
/-- An addition-preserving map between additive groups sends `0` to `0`:`f 0 + f 0 = f (0 + 0) = f 0 = f 0 + 0`, and cancelling `f 0` gives `f 0 = 0`.(Mathlib: `map_zero` for bundled homomorphisms.) -/theorem map_zero_of_preservesOp {A : Type u} {B : Type v} [AddGroup A] [AddGroup B] {f : A → B} (hf : PreservesOp f (· + ·) (· + ·)) : f 0 = 0 := by have h : f 0 + f 0 = f 0 + 0 := calc f 0 + f 0 = f (0 + 0) := (hf 0 0).symm _ = f 0 := by rw [add_zero] _ = f 0 + 0 := (add_zero _).symm exact add_left_cancel h
map_neg_of_preservesOptheoremProved here from basic factspropext
map_neg_of_preservesOpLean 4Proved here from basic factsFormally verified
/-- …and it sends negatives to negatives: `f (-x) + f x = f (-x + x) = f 0 = 0`, so`f (-x) = -f x`. (Mathlib: `map_neg`.) -/theorem map_neg_of_preservesOp {A : Type u} {B : Type v} [AddGroup A] [AddGroup B] {f : A → B} (hf : PreservesOp f (· + ·) (· + ·)) (x : A) : f (-x) = -f x := by have h : f (-x) + f x = 0 := calc f (-x) + f x = f (-x + x) := (hf (-x) x).symm _ = f 0 := by rw [neg_add_cancel] _ = 0 := map_zero_of_preservesOp hf exact eq_neg_of_add_eq_zero_left h
comm_of_surjectivetheoremProved here from basic factsNo axioms
comm_of_surjectiveLean 4Proved here from basic factsFormally verified
/-- **Structure transfers along homomorphisms.** If `f` preserves the operation and issurjective, and `∗` is commutative, then so is `⋆`: write `u = f x`, `v = f y`; then`u ⋆ v = f (x ∗ y) = f (y ∗ x) = v ⋆ u`. In particular isomorphic structures are either bothcommutative or both not. -/theorem comm_of_surjective {A : Type u} {B : Type v} {opA : A → A → A} {opB : B → B → B} {f : A → B} (hf : PreservesOp f opA opB) (hsurj : Function.Surjective f) (hcomm : ∀ x y, opA x y = opA y x) : ∀ u v, opB u v = opB v u := by intro u v obtain ⟨x, rfl⟩ := hsurj u obtain ⟨y, rfl⟩ := hsurj v rw [← hf, ← hf, hcomm]
/-- `ln` as a map `ℝ>0 → ℝ`. -/noncomputable def logPos (u : {y : ℝ // 0 < y}) : ℝ := Real.log u.1
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
expPos_preservestheoremProved here from basic factspropext, Classical.choice, Quot.sound
expPos_preservesLean 4Proved here from basic factsFormally verified
/-- `exp : (ℝ, +) → (ℝ>0, ×)` preserves the operations; two elements of a subtype are equalwhen their values are (`Subtype.ext`), so this is `Real.exp_add` again. -/theorem expPos_preserves : PreservesOp expPos (· + ·) posMul := fun x y => Subtype.ext (Real.exp_add x y)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
log_exp_inversetheoremProved here from basic factspropext, Classical.choice, Quot.sound
log_exp_inverseLean 4Proved here from basic factsFormally verified
/-- `ln` and `exp` are inverse to each other between `ℝ` and `ℝ>0`:`ln (exp x) = x` (`Real.log_exp`) and `exp (ln u) = u` for `u > 0` (`Real.exp_log`). -/theorem log_exp_inverse : Function.LeftInverse logPos expPos ∧ Function.RightInverse logPos expPos := ⟨fun x => Real.log_exp x, fun u => Subtype.ext (Real.exp_log u.2)⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
logPos_preservestheoremProved here from basic factspropext, Classical.choice, Quot.sound
logPos_preservesLean 4Proved here from basic factsFormally verified
/-- **`ln (uv) = ln u + ln v`, for free.** `exp` is a bijective homomorphism, so by`PreservesOp.inverse` its inverse `ln` is a homomorphism `(ℝ>0, ×) → (ℝ, +)`. We never touchthe definition of the logarithm. -/theorem logPos_preserves : PreservesOp logPos posMul (· + ·) := expPos_preserves.inverse log_exp_inverse.1 log_exp_inverse.2
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
no_injective_hom_zmod4_kleintheoremProved here from basic factspropext, Classical.choice, Quot.sound
no_injective_hom_zmod4_kleinLean 4Proved here from basic factsFormally verified
/-- **Clock arithmetic mod 4 is not isomorphic to the Klein four-group** `ℤ/2 × ℤ/2` — not evenby an injective homomorphism. In `ℤ/2 × ℤ/2` every element satisfies `x + x = 0`. If `f`preserved addition, then `f (1 + 1) = f 1 + f 1 = 0 = f 0 + f 0 = f (0 + 0)`, and injectivitywould give `1 + 1 = 0` in `ℤ/4`, which is false. -/theorem no_injective_hom_zmod4_klein : ¬ ∃ f : ZMod 4 → ZMod 2 × ZMod 2, Function.Injective f ∧ PreservesOp f (· + ·) (· + ·) := by rintro ⟨f, hinj, hf⟩ have hdouble : ∀ x : ZMod 2 × ZMod 2, x + x = 0 := by decide have h : f (1 + 1) = f (0 + 0) := calc f (1 + 1) = f 1 + f 1 := hf 1 1 _ = 0 := hdouble _ _ = f 0 + f 0 := (hdouble _).symm _ = f (0 + 0) := (hf 0 0).symm exact absurd (hinj h) (by decide)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
zmod4_not_iso_kleintheoremProved here from basic factspropext, Classical.choice, Quot.sound
zmod4_not_iso_kleinLean 4Proved here from basic factsFormally verified
/-- The same fact for Mathlib's bundled isomorphisms of additive groups (`≃+`): there is no`e : ZMod 4 ≃+ ZMod 2 × ZMod 2`, because `e` would be an injective homomorphism. -/theorem zmod4_not_iso_klein (e : ZMod 4 ≃+ ZMod 2 × ZMod 2) : False := no_injective_hom_zmod4_klein ⟨e, e.injective, fun x y => map_add e x y⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
crt6defDefinitionpropext, Quot.sound
crt6Lean 4Formally verified
/-- The map `ℤ/6 → ℤ/2 × ℤ/3`, `x ↦ (x mod 2, x mod 3)`. (`ZMod.cast` reduces a residuemod 6 to a residue mod 2 or mod 3; this is well defined because 2 and 3 divide 6.) -/def crt6 (x : ZMod 6) : ZMod 2 × ZMod 3 := (ZMod.cast x, ZMod.cast x)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
PreservesReldefDefinitionNo axioms
PreservesRelLean 4Formally verified
/-- For a **relation** (an order, the edges of a graph…), "preserving" means: related inputs haverelated outputs, `r x y → s (f x) (f y)`. -/def PreservesRel {A : Type u} {B : Type v} (f : A → B) (r : A → A → Prop) (s : B → B → Prop) : Prop := ∀ x y, r x y → s (f x) (f y)
bijection_not_isotheoremProved here from basic factspropext
bijection_not_isoLean 4Proved here from basic factsFormally verified
/-- **A structure-preserving bijection whose inverse does not preserve structure.** On `Bool`,compare the "discrete" order in which only `x ≤ x` holds (the relation `=`) with the usual order`false ≤ true`. The identity map is a bijection and preserves order from the discrete order tothe usual one; but its inverse (the identity again, read backwards) sends `false ≤ true` to`false = true`, which fails. So for relations, "bijective and preserving" does not imply"isomorphism". -/theorem bijection_not_iso : Function.Bijective (id : Bool → Bool) ∧ PreservesRel (id : Bool → Bool) (· = ·) (· ≤ ·) ∧ ¬ PreservesRel (id : Bool → Bool) (· ≤ ·) (· = ·) := by refine ⟨Function.bijective_id, ?_, ?_⟩ · intro x y h subst h exact le_refl x · intro h have hft : false = true := h false true (by decide) exact Bool.false_ne_true hft
coloring_is_homtheoremApplies a library theorempropext, Classical.choice, Quot.sound
coloring_is_homLean 4Applies a library theoremFormally verified
/-- In Mathlib, a **colouring** of a graph `G` with colours `α` is *defined* to be a graphhomomorphism from `G` to the complete graph on `α` (adjacent vertices must go to adjacent, thatis, different, colours). This holds by Mathlib's definition `SimpleGraph.Coloring`. -/theorem coloring_is_hom {V : Type u} (G : SimpleGraph V) (α : Type v) : G.Coloring α = (G →g SimpleGraph.completeGraph α) := rfl
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/StructurePreservingMaps.leanTry it in the Lean web editor
Formal exercises
Each exercise contains a sorry for you to replace. Open it in the Lean web editor, or clone the repository and run lake build.
/-- Composites of homomorphisms are homomorphisms.Hint: `intro x y`, then a `calc` block with three steps: unfold `(g ∘ f) (opA x y)` to`g (f (opA x y))` (`rfl`), rewrite with `hf`, finish with `hg`. -/theorem PreservesOp.comp {A : Type u} {B : Type v} {C : Type w} {opA : A → A → A} {opB : B → B → B} {opC : C → C → C} {f : A → B} {g : B → C} (hf : PreservesOp f opA opB) (hg : PreservesOp g opB opC) : PreservesOp (g ∘ f) opA opC := by sorry
Show the compiled solution
compLean 4Proved here from basic factsFormally verified
/-- **Composites of homomorphisms are homomorphisms.** If `f` turns `∗` into `⋆` and `g` turns`⋆` into `•`, then `g ∘ f` turns `∗` into `•`:`g(f(x ∗ y)) = g(f x ⋆ f y) = g(f x) • g(f y)`. -/theorem PreservesOp.comp {A : Type u} {B : Type v} {C : Type w} {opA : A → A → A} {opB : B → B → B} {opC : C → C → C} {f : A → B} {g : B → C} (hf : PreservesOp f opA opB) (hg : PreservesOp g opB opC) : PreservesOp (g ∘ f) opA opC := by intro x y calc (g ∘ f) (opA x y) = g (f (opA x y)) := rfl _ = g (opB (f x) (f y)) := by rw [hf] _ = opC (g (f x)) (g (f y)) := hg _ _
/-- A surjective homomorphism carries commutativity across.Hint: `obtain ⟨x, rfl⟩ := hsurj u` writes `u` as `f x`; do the same for `v`, then`rw [← hf, ← hf, hcomm]`. -/theorem comm_of_surjective {A : Type u} {B : Type v} {opA : A → A → A} {opB : B → B → B} {f : A → B} (hf : PreservesOp f opA opB) (hsurj : Function.Surjective f) (hcomm : ∀ x y, opA x y = opA y x) : ∀ u v, opB u v = opB v u := by sorry
Show the compiled solution
comm_of_surjectiveLean 4Proved here from basic factsFormally verified
/-- **Structure transfers along homomorphisms.** If `f` preserves the operation and issurjective, and `∗` is commutative, then so is `⋆`: write `u = f x`, `v = f y`; then`u ⋆ v = f (x ∗ y) = f (y ∗ x) = v ⋆ u`. In particular isomorphic structures are either bothcommutative or both not. -/theorem comm_of_surjective {A : Type u} {B : Type v} {opA : A → A → A} {opB : B → B → B} {f : A → B} (hf : PreservesOp f opA opB) (hsurj : Function.Surjective f) (hcomm : ∀ x y, opA x y = opA y x) : ∀ u v, opB u v = opB v u := by intro u v obtain ⟨x, rfl⟩ := hsurj u obtain ⟨y, rfl⟩ := hsurj v rw [← hf, ← hf, hcomm]