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..0bd93f4ddb 100644
--- a/lib/ringsc.gd
+++ b/lib/ringsc.gd
@@ -193,8 +193,13 @@ 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> R7 := SmallRing( 7, 2 );; SetName( R7, "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 ] );
+##
## ]]>
##
##
@@ -202,5 +207,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( R78, 1 );
+## [ a ] -> [ Aa ]
+## gap> a := GeneratorsOfRing( R7 )[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( R78, 2 );
+## [ Aa, Ba, Bb, Bc ] -> [ 0*a, a, b, c ]
+## gap> b := GeneratorsOfRing( R78 )[2];;
+## gap> ImageElm( pro2, 5*b );
+## a
+## ]]>
+##
+##
+## <#/GAPDoc>
diff --git a/lib/ringsc.gi b/lib/ringsc.gi
index 6f87c6ac3a..42c82b2f28 100644
--- a/lib/ringsc.gi
+++ b/lib/ringsc.gi
@@ -1101,7 +1101,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 +1114,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 +1208,71 @@ local ones,s, moduli, orders, offsets, o, p, newmod, t, nams, gens, e, f, D, i,
return D;
end );
+#############################################################################
+##
+#M Embedding( , )
+##
+InstallMethod( Embedding, "ring direct sum and integer",
+ [ IsSubringSCRing 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 := StandardGeneratorsSubringSCRing( R )[3];
+ imgs := GeneratorsOfRing( D ){[first[i]+1 .. first[i+1]]};
+ map := RingHomomorphismByImages( R, D, gens, imgs );
+ SetIsInjective( map, true );
+
+ # store information
+ info.embeddings[i] := map;
+ return map;
+end );
+
+#############################################################################
+##
+#M Projection( , )
+##
+InstallMethod( Projection, "ring direct sum and integer",
+ [ IsSubringSCRing 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 := StandardGeneratorsSubringSCRing( R )[3];
+ 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
diff --git a/tst/testinstall/ring-dsum.tst b/tst/testinstall/ring-dsum.tst
new file mode 100644
index 0000000000..98b71dc43f
--- /dev/null
+++ b/tst/testinstall/ring-dsum.tst
@@ -0,0 +1,86 @@
+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> #
+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");