diff --git a/lib/field.gi b/lib/field.gi index 281424d801..0031204602 100644 --- a/lib/field.gi +++ b/lib/field.gi @@ -1114,7 +1114,7 @@ InstallMethod( QuotientRemainder, if not r in F then TryNextMethod(); # FIXME: or error? fi; - return [ r/s, 0 ]; + return [ r/s, Zero(F) ]; end ); ############################################################################# diff --git a/lib/zmodnz.gd b/lib/zmodnz.gd index 71ded1bb9f..409ea3b812 100644 --- a/lib/zmodnz.gd +++ b/lib/zmodnz.gd @@ -127,6 +127,13 @@ InstallTrueMethod( IsFinite, IsZmodnZObjNonprimeCollection and IsDuplicateFree ); +############################################################################# +## +#M IsEuclideanRing( ) . . . . . . . . . . . . method for full ring Z/nZ +## +InstallTrueMethod(IsEuclideanRing, IsZmodnZObjNonprimeCollection and + IsWholeFamily and IsRing); + ############################################################################# ## #V Z_MOD_NZ @@ -241,7 +248,7 @@ DeclareSynonym( "ZmodpZObj", ZmodnZObj ); ## ## ## For an element obj in a residue class ring of integers modulo -## n (see ), +## n (see ), ## returns the positive integer n. ## ## Deprecated, use instead. diff --git a/lib/zmodnz.gi b/lib/zmodnz.gi index f801ab9df7..53204c8911 100644 --- a/lib/zmodnz.gi +++ b/lib/zmodnz.gi @@ -656,6 +656,43 @@ InstallMethod(ZOp, end); +############################################################################# +## +#M EuclideanDegree( , ) +## +## For an overview on the theory of euclidean rings which are not domains, +## see Pierre Samuel, "About Euclidean rings", J. Algebra, 1971 vol. 19 pp. 282-301. +## http://dx.doi.org/10.1016/0021-8693(71)90110-4 + +InstallMethod( EuclideanDegree, + "for Z/nZ and an element in Z/nZ", + IsCollsElms, + [ IsZmodnZObjNonprimeCollection and IsWholeFamily and IsRing, IsZmodnZObj and IsModulusRep ], + function ( R, n ) + return GcdInt( n![1], Characteristic( n ) ); + end ); + + +############################################################################# +## +#M QuotientRemainder( , , ) +## +InstallMethod( QuotientRemainder, + "for Z/nZ and two elements in Z/nZ", + IsCollsElmsElms, + [ IsZmodnZObjNonprimeCollection and IsWholeFamily and IsRing, + IsZmodnZObj and IsModulusRep, IsZmodnZObj and IsModulusRep ], + function ( R, n, m ) + local u, s, q, r; + u := StandardAssociateUnit(R, m); + s := u * m; # the standard associate of m + q := QuoInt(n![1], s![1]); + r := n![1] - q * s![1]; + return [ ZmodnZObj( FamilyObj( n ), (q * u![1]) mod Characteristic(R) ), + ZmodnZObj( FamilyObj( n ), r ) ]; + end ); + + ############################################################################# ## #M StandardAssociate( ) diff --git a/tst/testinstall/euclidean.tst b/tst/testinstall/euclidean.tst new file mode 100644 index 0000000000..ca3b3285db --- /dev/null +++ b/tst/testinstall/euclidean.tst @@ -0,0 +1,60 @@ +#@local checkEuclideanRing +gap> START_TEST("euclidean.tst"); + +# test consistency of EuclideanDegree, EuclideanQuotient, EuclideanRemainder, +# and QuotientRemainder for some ring and elements of it +gap> checkEuclideanRing := +> function(R, colls...) +> local coll1, coll2, a, b, deg_b, deg_r, q, r, qr; +> if Length(colls) >= 1 then coll1:=colls[1]; +> elif Size(R) <= 100 then coll1 := R; +> else coll1 := List([1..100],i->Random(R)); +> fi; +> if Length(colls) >= 2 then coll2:=colls[2]; +> elif Size(R) <= 100 then coll2 := R; +> else coll2 := List([1..100],i->Random(R)); +> fi; +> for b in coll1 do +> if IsZero(b) then continue; fi; +> deg_b := EuclideanDegree(R, b); +> for a in coll2 do +> q := EuclideanQuotient(R, a, b); Assert(0, q in R); +> r := EuclideanRemainder(R, a, b); Assert(0, r in R); +> if a <> q*b + r then Error("a <> q*b + r for ", [R,a,b]); fi; +> deg_r := EuclideanDegree(R, r); +> if not IsZero(r) and deg_r >= deg_b then Error("Euclidean degree did not decrease for ",[R,a,b]); fi; +> qr := QuotientRemainder(R, a, b); +> if qr <> [q, r] then Error("QuotientRemainder inconsistent for ", [R,a,b]); fi; +> od; +> od; +> return true; +> end;; + +# rings in characteristic 0 +gap> checkEuclideanRing(Integers,[-100..100],[-100..100]); +true +gap> checkEuclideanRing(Rationals); +true +gap> checkEuclideanRing(GaussianIntegers); +true +gap> checkEuclideanRing(GaussianRationals); +true + +# finite fields +gap> ForAll(Filtered([2..50], IsPrimePowerInt), q->checkEuclideanRing(GF(q))); +true + +# ZmodnZ +gap> ForAll([1..50], m -> checkEuclideanRing(Integers mod m)); +true +gap> checkEuclideanRing(Integers mod ((2*3*5)^2)); +true +gap> checkEuclideanRing(Integers mod ((2*3*5)^3)); +true +gap> checkEuclideanRing(Integers mod ((2*3*5*7)^2)); +true +gap> checkEuclideanRing(Integers mod ((2*3*5*7)^3)); +true + +# +gap> STOP_TEST( "euclidean.tst", 1);