1-- Ring homomorphisms f : R →+* S between bundled rings: maps preserving2-- the operations and constants, the bridges to the form over separate3-- pieces, the preservation laws, identity and composite homomorphisms, the4-- kernel ideal, and isomorphisms f : R ≃+* S; everything here is ZF5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Algebra.Ring.Homomorphism11import HomomorphismCore12import Quotient1314-- f : R →+* S: a function between the carriers preserving zero, one,15-- negation, addition, and multiplication. The form is a transparent16-- guard, so a hypothesis f : R →+* S also supplies the rings R and S, their17-- operations, and the binders (a : R) and (b : S). IsRingHom(f, A, add,18-- …, B, plus, …) remains the form over separate pieces, bridged below.19predicate RingHom (f R S : Set) :=20 Ring(R) ∧ Ring(S) ∧ (f : R.carrier → S.carrier) ∧21 f(R[0]) = S[0] ∧ f(R[1]) = S[1] ∧ (∀ x ∈ R, f(-x) = -f(x)) ∧22 (∀ x y ∈ R, f(x + y) = f(x) + f(y)) ∧23 (∀ x y ∈ R, f(x * y) = f(x) * f(y))24predicate RingIso (f R S : Set) :=25 RingHom(f, R, S) ∧ BijectiveBetween(f, R.carrier, S.carrier)2627notationguard"_ : _ →+* _"=> RingHom28notationguard"_ : _ ≃+* _"=> RingIso2930-- The kernel of f : R →+* S is written ker(f) wherever a hypothesis in31-- scope supplies the homomorphism, and is the set ringKernel(f, R.carrier,32-- S.zero) of the elements sent to zero.33notation function "ker(f)"=> ringKernel(f, R, S[0]) viahypothesis RingHom(f, R, S)3435-- Bridges between the bundled homomorphism and the form over separate36-- pieces: the bundled-to-unbundled direction is an instance.37instance RingHom.parts (f R S : Set)38requires hom : f : R→+* S39shows IsRingHom(f, R.carrier, R.add, R.zero, R.neg, R.mul, R.one,40 S.carrier, S.add, S.zero, S.neg, S.mul, S.one)41proof42obtain⟨source, target, function, zero, one, neg, add, mul⟩:= hom43unfold IsRingHom44exact⟨function, zero, one, neg, add, mul⟩4546theorem RingHom.of_projections (f R S : Set)47requires source : Ring(R)48requires target : Ring(S)49requires hom : IsRingHom(f, R.carrier, R.add, R.zero, R.neg, R.mul, R.one,50 S.carrier, S.add, S.zero, S.neg, S.mul, S.one)51shows f : R→+* S52proof53obtain⟨function, zero, one, neg, add, mul⟩:= hom54unfold Homomorphism.RingHom55exact⟨source, target, function, zero, one, neg, add, mul⟩5657theorem RingHom.of_parts (f A add zero neg mul one B plus z minus times unit : Set)58requires source : IsRing(A, add, zero, neg, mul, one)59requires target : IsRing(B, plus, z, minus, times, unit)60requires hom : IsRingHom(f, A, add, zero, neg, mul, one, B, plus, z, minus, times, unit)61shows f : Ring.mk(A, add, zero, neg, mul, one) →+* Ring.mk(B, plus, z, minus, times, unit)62proof63have bundledSource := Ring.of_parts with source64have bundledTarget := Ring.of_parts with target65have shifted : IsRingHom(f, Ring.carrier(Ring.mk(A, add, zero, neg, mul, one)),66 Ring.add(Ring.mk(A, add, zero, neg, mul, one)),67 Ring.zero(Ring.mk(A, add, zero, neg, mul, one)),68 Ring.neg(Ring.mk(A, add, zero, neg, mul, one)),69 Ring.mul(Ring.mk(A, add, zero, neg, mul, one)),70 Ring.one(Ring.mk(A, add, zero, neg, mul, one)),71 Ring.carrier(Ring.mk(B, plus, z, minus, times, unit)),72 Ring.add(Ring.mk(B, plus, z, minus, times, unit)),73 Ring.zero(Ring.mk(B, plus, z, minus, times, unit)),74 Ring.neg(Ring.mk(B, plus, z, minus, times, unit)),75 Ring.mul(Ring.mk(B, plus, z, minus, times, unit)),76 Ring.one(Ring.mk(B, plus, z, minus, times, unit)))77 ring_projections78exact RingHom.of_projections with bundledSource, bundledTarget, shifted7980instance RingIso.parts (f R S : Set)81requires iso : f : R≃+* S82shows IsRingIso(f, R.carrier, R.add, R.zero, R.neg, R.mul, R.one,83 S.carrier, S.add, S.zero, S.neg, S.mul, S.one)84proof85obtain⟨hom, bijective⟩:= iso86have parts := RingHom.parts with hom87unfold IsRingIso88exact⟨parts, bijective⟩8990theorem RingIso.of_projections (f R S : Set)91requires source : Ring(R)92requires target : Ring(S)93requires iso : IsRingIso(f, R.carrier, R.add, R.zero, R.neg, R.mul, R.one,94 S.carrier, S.add, S.zero, S.neg, S.mul, S.one)95shows f : R≃+* S96proof97obtain⟨hom, bijective⟩:= iso98have bundled := RingHom.of_projections with source, target, hom99unfold Homomorphism.RingIso100exact⟨bundled, bijective⟩101102-- The constructor: between commutative rings the three usual laws suffice,103-- zero and negation being preserved as a consequence.104theorem RingHom.mk (f R S : Set)105requires source : CommRing(R)106requires target : CommRing(S)107requires function : f : R.carrier → S.carrier108requires additive : ∀ x y ∈ R, f(x + y) = f(x) + f(y)109requires multiplicative : ∀ x y ∈ R, f(x * y) = f(x) * f(y)110requires unital : f(R[1]) = S[1]111shows f : R→+* S112proof113have sourceParts := CommRing.parts with source114have targetParts := CommRing.parts with target115have engine := IsRingHom.of_add_mul_one with sourceParts, targetParts,116 function, additive, multiplicative, unital117exact RingHom.of_projections with (CommRing.to_ring with source),118 (CommRing.to_ring with target), engine119120section HomLaws121variable (f R S : Set)122hypothesis hom : f : R→+* S123124theorem RingHom.source125shows Ring(R)126proof127obtain⟨source, rest⟩:= hom128exact source129130theorem RingHom.target131shows Ring(S)132proof133obtain⟨source, target, rest⟩:= hom134exact target135136-- The preservation laws, under their standard names.137instance RingHom.map_mem (a : R)138shows f(a) ∈ S139proof140obtain⟨source, target, function, rest⟩:= hom141exact FunctionBetween.apply_closed with function, *142143theorem RingHom.map_zero144shows f(R[0]) = S[0]145proof146obtain⟨source, target, function, zero, rest⟩:= hom147exact zero148149theorem RingHom.map_one150shows f(R[1]) = S[1]151proof152obtain⟨source, target, function, zero, one, rest⟩:= hom153exact one154155theorem RingHom.map_neg (a : R)156shows f(-a) = -f(a)157proof158obtain⟨source, target, function, zero, one, neg, rest⟩:= hom159have aIn : a ∈ R byassumption160exact neg with a, aIn161162theorem RingHom.map_add (a b : R)163shows f(a + b) = f(a) + f(b)164proof165obtain⟨source, target, function, zero, one, neg, add, mul⟩:= hom166have aIn : a ∈ R byassumption167have bIn : b ∈ R byassumption168exact add with a, aIn, b, bIn169170theorem RingHom.map_mul (a b : R)171shows f(a * b) = f(a) * f(b)172proof173obtain⟨source, target, function, zero, one, neg, add, mul⟩:= hom174have aIn : a ∈ R byassumption175have bIn : b ∈ R byassumption176exact mul with a, aIn, b, bIn177178theorem RingHom.map_sub (a b : R)179shows f(a - b) = f(a) - f(b)180proof181have source := RingHom.source with hom182have target := RingHom.target with hom183have fa : f(a) ∈ S := RingHom.map_mem with*184have fb : f(b) ∈ S := RingHom.map_mem with*185have negIn : -b ∈ R := Ring.neg_mem with*186rw [Ring.sub.value, Ring.sub.value, RingHom.map_add, RingHom.map_neg]187rfl188189-- The kernel: the elements sent to zero, an ideal of the source when the190-- rings are commutative, and the measure of equal images.191theorem RingHom.mem_kernel_iff (x : R)192shows x ∈ ker(f) ↔ f(x) = S[0]193proof194have xIn : x ∈ R byassumption195constructor196 . intro member197have data := ringKernel.membership.forward with member198exact data.right199 . intro vanishes200exact ringKernel.membership.backward with⟨xIn, vanishes⟩201202theorem RingHom.kernel_subset203shows ker(f) ⊆ R204proof205intros x hx206have data := ringKernel.membership.forward with hx207exact data.left208209theorem RingHom.zero_mem_kernel210shows R[0] ∈ ker(f)211proof212have source := RingHom.source with hom213have zeroIn : R[0] ∈ R := Ring.zero_mem with*214have vanishes := RingHom.map_zero with hom215exact ringKernel.membership.backward with⟨zeroIn, vanishes⟩216217theorem RingHom.ext (g : Set)218requires hom2 : g : R→+* S219requires same : ∀ x ∈ R, f(x) = g(x)220shows f = g221proof222obtain⟨source, target, function, rest⟩:= hom223obtain⟨source2, target2, function2, rest2⟩:= hom2224exact FunctionBetween.ext with function, function2, same225226end HomLaws227228section CommutativeHomLaws229variable (f R S : Set)230hypothesis source : CommRing(R)231hypothesis target : CommRing(S)232hypothesis hom : f : R→+* S233234theorem ringKernel.ideal235shows Ideal(R, ker(f))236proof237have sourceParts := CommRing.parts with source238have targetParts := CommRing.parts with target239have parts := RingHom.parts with hom240have engine := IsRingHom.kernel_ideal with sourceParts, targetParts, parts241exact Ideal.of_projections with engine242243theorem RingHom.apply_eq_iff (x y : R)244shows f(x) = f(y) ↔ x - y ∈ ker(f)245proof246have sourceParts := CommRing.parts with source247have targetParts := CommRing.parts with target248have parts := RingHom.parts with hom249have xIn : x ∈ R byassumption250have yIn : y ∈ R byassumption251have criterion := IsRingHom.kernel_congruent with sourceParts, targetParts,252 parts, xIn, yIn253rw Ring.sub.value254constructor255 . intro equal256have same := criterion.backward with equal257unfold Congruent at same258exact same259 . intro member260have same : Congruent(R.add, R.neg, ringKernel(f, R.carrier, S.zero), x, y)261unfold Congruent262exact member263exact criterion.forward with same264265end CommutativeHomLaws266267-- Identity and composite homomorphisms.268theorem RingHom.id (R : Set)269requires comm : CommRing(R)270shows identity(R.carrier) : R→+* R271proof272have parts := CommRing.parts with comm273have engine := IsRingHom.identity with parts274exact RingHom.of_projections with (CommRing.to_ring with comm),275 (CommRing.to_ring with comm), engine276277theorem RingHom.comp (f g R S T : Set)278requires comm : CommRing(R)279requires first : f : R→+* S280requires second : g : S →+* T281shows compose(g, f, R.carrier, S.carrier, T.carrier) : R→+* T282proof283have parts := CommRing.parts with comm284have firstParts := RingHom.parts with first285have secondParts := RingHom.parts with second286have engine := IsRingHom.compose with parts, firstParts, secondParts287exact RingHom.of_projections with (RingHom.source with first),288 (RingHom.target with second), engine289290-- An isomorphism is a homomorphism, and its inverse graph is one too.291theorem RingIso.hom_of (f R S : Set)292requires iso : f : R≃+* S293shows f : R→+* S294proof295obtain⟨hom, bijective⟩:= iso296exact hom297298theorem RingIso.bijective_of (f R S : Set)299requires iso : f : R≃+* S300shows BijectiveBetween(f, R.carrier, S.carrier)301proof302obtain⟨hom, bijective⟩:= iso303exact bijective304305theorem RingIso.symm (f R S : Set)306requires source : CommRing(R)307requires target : CommRing(S)308requires iso : f : R≃+* S309shows converse(f, R.carrier, S.carrier) : S ≃+* R310proof311have sourceParts := CommRing.parts with source312have targetParts := CommRing.parts with target313have parts := RingIso.parts with iso314have engine := IsRingIso.inverse with sourceParts, targetParts, parts315exact RingIso.of_projections with (CommRing.to_ring with target),316 (CommRing.to_ring with source), engine317