From dc18b49cdba606bcb56caef10984c4928643cb76 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 8 Oct 2026 10:48:48 +0100 Subject: [PATCH 1/7] embedding and projection for direct sums of rings --- doc/ref/rings.xml | 2 ++ lib/ringsc.gd | 55 ++++++++++++++++++++++++++++++++++-- lib/ringsc.gi | 72 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/doc/ref/rings.xml b/doc/ref/rings.xml index eeb571699a..991cb28e34 100644 --- a/doc/ref/rings.xml +++ b/doc/ref/rings.xml @@ -189,6 +189,8 @@ see . <#Include Label="Subrings"> <#Include Label="Ideals"> <#Include Label="DirectSum"> +<#Include Label="Embedding:rings"> +<#Include Label="Projection:rings"> <#Include Label="RingByStructureConstants"> diff --git a/lib/ringsc.gd b/lib/ringsc.gd index 01d73541c9..b6b56176b8 100644 --- a/lib/ringsc.gd +++ b/lib/ringsc.gd @@ -193,7 +193,9 @@ DeclareGlobalFunction("SmallRing"); ## (This somewhat strange syntax allows the method selection to choose ## a reasonable method for special cases.) ## DirectSum(SmallRing(5,1),SmallRing(5,1)); +## gap> R5 := SmallRing( 5, 2 );; SetName( R5, "R5" ); +## gap> R7 := SmallRing( 7, 2 );; SetName( R7, "R7" ); +## gap> R57 := DirectSum( R5, R7 ); ## ## ]]> ## @@ -202,5 +204,54 @@ DeclareGlobalFunction("SmallRing"); ## DeclareGlobalFunction( "DirectSum" ); DeclareOperation( "DirectSumOp", [ IsList, IsRing ] ); -DeclareAttribute( "DirectSumInfo", IsGroup, "mutable" ); +DeclareAttribute( "DirectSumInfo", IsRing, "mutable" ); +############################################################################# +## +#O Embedding( , ) +## +## <#GAPDoc Label="Embedding:rings"> +## +## +## +## +## If ring R is the direct sum of rings [R_1,\ldots,R_k] +## then Embedding(R,i) for 1 \leq i \leq k returns a ring +## homomorphism mapping R_i into R. +##

+## emb1 := Embedding( R57, 1 ); +## [ a ] -> [ Aa ] +## gap> a := GeneratorsOfRing( R5 )[1];; +## gap> ImageElm( emb1, 3*a ); +## 3*Aa +## ]]> +## +## +## <#/GAPDoc> + +############################################################################# +## +#O Projection( , ) +## +## <#GAPDoc Label="Projection:rings"> +## +## +## +## +## If ring R is the direct sum of rings [R_1,\ldots,R_k] +## then Projection(R,i) for 1 \leq i \leq k returns a ring +## homomorphism mapping R onto R_i. +##

+## pro2 := Projection( R57, 2 ); +## [ Aa, Ba ] -> [ 0*a, a ] +## gap> b := GeneratorsOfRing( R57 )[2];; +## gap> ImageElm( pro2, 4*b ); +## 4*a +## ]]> +## +## +## <#/GAPDoc> diff --git a/lib/ringsc.gi b/lib/ringsc.gi index 6f87c6ac3a..3eb6973f87 100644 --- a/lib/ringsc.gi +++ b/lib/ringsc.gi @@ -1072,7 +1072,6 @@ local d,t,i; fi; od; fi; - d:=DirectSumOp( arg, arg[1] ); if ForAll(arg,HasSize) then if ForAll(arg,IsFinite) @@ -1101,7 +1100,7 @@ local ids, tup, first, i, G, gens, g, new, D; ids := List( list, Zero ); tup := []; - first := [1]; + first := [0]; for i in [1..Length( list )] do G := list[i]; gens := GeneratorsOfRing( G ); @@ -1114,7 +1113,7 @@ local ids, tup, first, i, G, gens, g, new, D; new := DirectProductElement( new ); Add( tup, new ); od; - Add( first, Length( tup )+1 ); + Add( first, Length( tup ) ); od; D := RingByGenerators( tup ); @@ -1208,6 +1207,73 @@ local ones,s, moduli, orders, offsets, o, p, newmod, t, nams, gens, e, f, D, i, return D; end ); +############################################################################# +## +#A Embedding +## +InstallMethod( Embedding, "ring direct sum and integer", + [ IsRing and HasDirectSumInfo, IsPosInt ], + function( D, i ) + local info, first, R, gens, imgs, map; + + # check + info := DirectSumInfo( D ); + if IsBound( info.embeddings[i] ) then + return info.embeddings[i]; + fi; + first := info.first; + if not ( i < Length(first) ) then + Error( "value of second parameter is too large" ); + fi; + # compute embedding + R := info.rings[i]; + gens := GeneratorsOfRing( R ); + imgs := GeneratorsOfRing( D ){[first[i]+1 .. first[i+1]]}; + map := RingHomomorphismByImages( R, D, gens, imgs ); + SetIsInjective( map, true ); + SetIsTotal( map, true ); + SetIsSingleValued( map, true ); + + # store information + info.embeddings[i] := map; + return map; +end ); + +############################################################################# +## +#A Projection +## +InstallMethod( Projection, "ring direct sum and integer", + [ IsRing and HasDirectSumInfo, IsPosInt ], + function( D, i ) + local infoD, first, zR, len, R, genR, genD, imgs, j, k, map; + + infoD := DirectSumInfo( D ); + if IsBound( infoD.projections[i] ) then + return infoD.projections[i]; + fi; + first := infoD.first; + len := Length( first ); + if not ( i < len ) then + Error( "value of second parameter is too large" ); + fi; + # compute projection + R := infoD.rings[i]; + zR := Zero( R ); + genR := GeneratorsOfRing( R ); + genD := GeneratorsOfRing( D ); + imgs := ListWithIdenticalEntries( first[len], zR ); + j := first[i]; + for k in [first[i]+1..first[i+1]] do + imgs[k] := genR[k-j]; + od; + map := RingHomomorphismByImages( D, R, genD, imgs ); + + # store information + infoD.projections[i] := map; + return map; +end ); + ############################################################################# ## #M \+( , ) . . . . . . . . . . . . . . . . sum of rings From 6a767839f66bb42e21428031cc9a9a16f5124c5a Mon Sep 17 00:00:00 2001 From: cdwensley Date: Sat, 10 Oct 2026 12:26:08 +0100 Subject: [PATCH 2/7] processing comments from Max --- lib/ringsc.gd | 4 +- lib/ringsc.gi | 9 +++-- tst/testinstall/ring-dsum.tst | 70 +++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 tst/testinstall/ring-dsum.tst diff --git a/lib/ringsc.gd b/lib/ringsc.gd index b6b56176b8..da12417a36 100644 --- a/lib/ringsc.gd +++ b/lib/ringsc.gd @@ -212,7 +212,7 @@ DeclareAttribute( "DirectSumInfo", IsRing, "mutable" ); ## ## <#GAPDoc Label="Embedding:rings"> ## -## ## ## @@ -237,7 +237,7 @@ DeclareAttribute( "DirectSumInfo", IsRing, "mutable" ); ## ## <#GAPDoc Label="Projection:rings"> ## -## ## ## diff --git a/lib/ringsc.gi b/lib/ringsc.gi index 3eb6973f87..24ebdcd5e9 100644 --- a/lib/ringsc.gi +++ b/lib/ringsc.gi @@ -1072,6 +1072,7 @@ local d,t,i; fi; od; fi; + d:=DirectSumOp( arg, arg[1] ); if ForAll(arg,HasSize) then if ForAll(arg,IsFinite) @@ -1212,7 +1213,7 @@ end ); #A Embedding ## InstallMethod( Embedding, "ring direct sum and integer", - [ IsRing and HasDirectSumInfo, IsPosInt ], + [ IsSubringSCRing and HasDirectSumInfo, IsPosInt ], function( D, i ) local info, first, R, gens, imgs, map; @@ -1227,7 +1228,7 @@ InstallMethod( Embedding, "ring direct sum and integer", fi; # compute embedding R := info.rings[i]; - gens := GeneratorsOfRing( R ); + gens := StandardGeneratorsSubringSCRing( R )[3]; imgs := GeneratorsOfRing( D ){[first[i]+1 .. first[i+1]]}; map := RingHomomorphismByImages( R, D, gens, imgs ); SetIsInjective( map, true ); @@ -1244,7 +1245,7 @@ end ); #A Projection ## InstallMethod( Projection, "ring direct sum and integer", - [ IsRing and HasDirectSumInfo, IsPosInt ], + [ IsSubringSCRing and HasDirectSumInfo, IsPosInt ], function( D, i ) local infoD, first, zR, len, R, genR, genD, imgs, j, k, map; @@ -1260,7 +1261,7 @@ InstallMethod( Projection, "ring direct sum and integer", # compute projection R := infoD.rings[i]; zR := Zero( R ); - genR := GeneratorsOfRing( R ); + genR := StandardGeneratorsSubringSCRing( R )[3]; genD := GeneratorsOfRing( D ); imgs := ListWithIdenticalEntries( first[len], zR ); j := first[i]; diff --git a/tst/testinstall/ring-dsum.tst b/tst/testinstall/ring-dsum.tst new file mode 100644 index 0000000000..ea5b502287 --- /dev/null +++ b/tst/testinstall/ring-dsum.tst @@ -0,0 +1,70 @@ +gap> START_TEST("ring-dsum.tst"); +gap> # direct sums of small rings +gap> R7 := SmallRing( 7, 2 );; SetName( R7, "R7" ); +gap> R8 := SmallRing( 8, 52 );; SetName( R8, "R8" ); +gap> R9 := SmallRing( 9, 11 );; SetName( R9, "R9" ); +gap> R78 := DirectSum( R7, R8 ); + +gap> info78 := DirectSumInfo( R78 ); +rec( embeddings := [ ], first := [ 0, 1, 4 ], projections := [ ], + rings := [ R7, R8 ] ) +gap> R789 := DirectSum( [ R7, R8, R9 ] ); + +gap> info789 := DirectSumInfo( R789 ); +rec( embeddings := [ ], first := [ 0, 1, 4, 6 ], projections := [ ], + rings := [ R7, R8, R9 ] ) +gap> # +gap> # embeddings and projections of small rings +gap> Embedding( R78, 2 ); +[ a, b, c ] -> [ Ba, Bb, Bc ] +gap> e3 := Embedding( R789, 3 ); +[ a, b ] -> [ Ca, Cb ] +gap> Projection( R78, 1 ); +[ Aa, Ba, Bb, Bc ] -> [ a, 0*a, 0*a, 0*a ] +gap> p3 := Projection( R789, 3 ); +[ Aa, Ba, Bb, Bc, Ca, Cb ] -> [ 0*a, 0*a, 0*a, 0*a, a, b ] +gap> genR9 := GeneratorsOfRing( R9 );; +gap> a := genR9[1];; b := genR9[2];; +gap> [ a*b^2, ImageElm( e3, a*b^2 ) ]; +[ -a, -Ca ] +gap> ForAll( genR9, g -> ( g ^ e3 ) ^ p3 = g ); +true +gap> genR789 := GeneratorsOfRing( R789 );; +gap> x := genR789[3];; y := genR789[6];; +gap> [ x^2, ImageElm( p3, x^2 ) ]; +[ Ba+Bc, 0*a ] +gap> [ y^2, ImageElm( p3, y^2 ) ]; +[ -Ca, -a ] +gap> # +gap> # other direct sums of rings +gap> R4 := ZmodnZ( 4 );; +gap> R5 := ZmodnZ( 5 );; +gap> R6 := ZmodnZ( 6 );; +gap> R45 := DirectSum( R4, R5 ); + +gap> info45 := DirectSumInfo( R45 ); +rec( embeddings := [ ], first := [ 0, 2, 3 ], projections := [ ], + rings := [ (Integers mod 4), GF(5) ] ) +gap> R456 := DirectSum( [ R4, R5, R6 ] ); + +gap> info456 := DirectSumInfo( R456 ); +rec( embeddings := [ ], first := [ 0, 2, 3, 5 ], projections := [ ], + rings := [ (Integers mod 4), GF(5), (Integers mod 6) ] ) +gap> # +gap> # embeddings and projections of these rings: methods for these +gap> # operations are only installed for rings of type IsSubringSCRing +gap> Embedding( R45, 1 ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `Embedding' on 2 arguments +gap> Projection( R456, 2 ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `Projection' on 2 arguments +gap> # +gap> # combine these all together: +gap> D := DirectSum( [R4,R5,R6,R7,R8,R9] ); + +gap> DirectSumInfo( D ); +rec( embeddings := [ ], first := [ 0, 2, 3, 5, 6, 9, 11 ], + projections := [ ], + rings := [ (Integers mod 4), GF(5), (Integers mod 6), R7, R8, R9 ] ) +gap> STOP_TEST("ring-dsum.tst"); From 1460361a5938621a87700ca81881e432025d3b6a Mon Sep 17 00:00:00 2001 From: cdwensley Date: Sat, 10 Oct 2026 12:51:46 +0100 Subject: [PATCH 3/7] changed manual example to be closer to the test file --- lib/ringsc.gd | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/ringsc.gd b/lib/ringsc.gd index da12417a36..0bd93f4ddb 100644 --- a/lib/ringsc.gd +++ b/lib/ringsc.gd @@ -193,10 +193,13 @@ DeclareGlobalFunction("SmallRing"); ## (This somewhat strange syntax allows the method selection to choose ## a reasonable method for special cases.) ## R5 := SmallRing( 5, 2 );; SetName( R5, "R5" ); ## gap> R7 := SmallRing( 7, 2 );; SetName( R7, "R7" ); -## gap> R57 := DirectSum( R5, R7 ); -## +## gap> R8 := SmallRing( 8, 52 );; SetName( R8, "R8" ); +## gap> R78 := DirectSum( R7, R8 ); +## +## gap> R9 := SmallRing( 9, 11 );; SetName( R9, "R9" ); +## gap> R789 := DirectSum( [ R7, R8, R9 ] ); +## ## ]]> ## ## @@ -221,9 +224,9 @@ DeclareAttribute( "DirectSumInfo", IsRing, "mutable" ); ## homomorphism mapping R_i into R. ##

## emb1 := Embedding( R57, 1 ); +## gap> emb1 := Embedding( R78, 1 ); ## [ a ] -> [ Aa ] -## gap> a := GeneratorsOfRing( R5 )[1];; +## gap> a := GeneratorsOfRing( R7 )[1];; ## gap> ImageElm( emb1, 3*a ); ## 3*Aa ## ]]> @@ -246,11 +249,11 @@ DeclareAttribute( "DirectSumInfo", IsRing, "mutable" ); ## homomorphism mapping R onto R_i. ##

## pro2 := Projection( R57, 2 ); -## [ Aa, Ba ] -> [ 0*a, a ] -## gap> b := GeneratorsOfRing( R57 )[2];; -## gap> ImageElm( pro2, 4*b ); -## 4*a +## gap> pro2 := Projection( R78, 2 ); +## [ Aa, Ba, Bb, Bc ] -> [ 0*a, a, b, c ] +## gap> b := GeneratorsOfRing( R78 )[2];; +## gap> ImageElm( pro2, 5*b ); +## a ## ]]> ## ## From 9c19fe302ce7e11ff972fadb6078f229d95a1a44 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 14 Oct 2026 18:47:30 +0100 Subject: [PATCH 4/7] Update tst/testinstall/ring-dsum.tst Co-authored-by: Max Horn --- tst/testinstall/ring-dsum.tst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tst/testinstall/ring-dsum.tst b/tst/testinstall/ring-dsum.tst index ea5b502287..98b71dc43f 100644 --- a/tst/testinstall/ring-dsum.tst +++ b/tst/testinstall/ring-dsum.tst @@ -67,4 +67,20 @@ gap> DirectSumInfo( D ); rec( embeddings := [ ], first := [ 0, 2, 3, 5, 6, 9, 11 ], projections := [ ], rings := [ (Integers mod 4), GF(5), (Integers mod 6), R7, R8, R9 ] ) +gap> # +gap> # subrings whose generators are not the standard generators +gap> R3 := SmallRing( 3, 2 );; +gap> T3 := Subring( R3, [ -GeneratorsOfRing( R3 )[1] ] );; +gap> D3 := DirectSum( T3, T3 );; +gap> e := Embedding( D3, 2 );; p := Projection( D3, 2 );; +gap> ForAll( T3, r -> ( r ^ e ) ^ p = r ); +true +gap> ForAll( T3, r -> IsZero( ( r ^ e ) ^ Projection( D3, 1 ) ) ); +true +gap> S4 := SmallRing( 4, 1 );; g := GeneratorsOfRing( S4 )[1];; +gap> T4 := Subring( S4, [ 2*g, g ] );; +gap> D4 := DirectSum( T4, R3 );; +gap> e := Embedding( D4, 1 );; p := Projection( D4, 1 );; +gap> ForAll( T4, r -> ( r ^ e ) ^ p = r ); +true gap> STOP_TEST("ring-dsum.tst"); From f727e5a90637f99c3d1af8b37727d58b2e49e657 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 14 Oct 2026 18:53:48 +0100 Subject: [PATCH 5/7] Update lib/ringsc.gi Co-authored-by: Max Horn --- lib/ringsc.gi | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ringsc.gi b/lib/ringsc.gi index 24ebdcd5e9..45458b001b 100644 --- a/lib/ringsc.gi +++ b/lib/ringsc.gi @@ -1232,8 +1232,6 @@ InstallMethod( Embedding, "ring direct sum and integer", imgs := GeneratorsOfRing( D ){[first[i]+1 .. first[i+1]]}; map := RingHomomorphismByImages( R, D, gens, imgs ); SetIsInjective( map, true ); - SetIsTotal( map, true ); - SetIsSingleValued( map, true ); # store information info.embeddings[i] := map; From 4fbb08119443c3acb6d90e2aaa0a578c2b5b97ee Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 14 Oct 2026 18:54:43 +0100 Subject: [PATCH 6/7] Update lib/ringsc.gi Co-authored-by: Max Horn --- lib/ringsc.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ringsc.gi b/lib/ringsc.gi index 45458b001b..33ceab7b2a 100644 --- a/lib/ringsc.gi +++ b/lib/ringsc.gi @@ -1210,7 +1210,7 @@ end ); ############################################################################# ## -#A Embedding +#M Embedding( , ) ## InstallMethod( Embedding, "ring direct sum and integer", [ IsSubringSCRing and HasDirectSumInfo, IsPosInt ], From 7531248797cfce66b76443b5877ef91b31fe29ce Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 14 Oct 2026 18:54:52 +0100 Subject: [PATCH 7/7] Update lib/ringsc.gi Co-authored-by: Max Horn --- lib/ringsc.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ringsc.gi b/lib/ringsc.gi index 33ceab7b2a..42c82b2f28 100644 --- a/lib/ringsc.gi +++ b/lib/ringsc.gi @@ -1240,7 +1240,7 @@ end ); ############################################################################# ## -#A Projection +#M Projection( , ) ## InstallMethod( Projection, "ring direct sum and integer", [ IsSubringSCRing and HasDirectSumInfo, IsPosInt ],