From fe11ed7b10adb0b4908ad32896ea44281b92ecdd Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 17 May 2018 16:47:15 +0200 Subject: [PATCH] Improve Is{Constant,Univariate}RationalFunction, add tests * Change IsConstantRationalFunction and IsUnivariateRationalFunction to return false for objects which are not even rational functions * Improve UNIVARTEST_RATFUN to deal with some more "trivial" cases before giving up * Add convenience helpers for multiplying rational numbers by rational functions over rings which don't contain the rational numbers, complementing the existing helpers doing this for addition * Add tests --- hpcgap/lib/ratfun.gi | 33 +++++++++ lib/ratfun.gd | 2 +- lib/ratfun.gi | 33 +++++++++ lib/ratfun1.gi | 19 +++++ tst/testinstall/ratfun.tst | 94 ++++++++++++++++++++----- tst/testinstall/ratfun_gf5.tst | 124 +++++++++++++++++++++++++++++++++ 6 files changed, 285 insertions(+), 20 deletions(-) create mode 100644 tst/testinstall/ratfun_gf5.tst diff --git a/hpcgap/lib/ratfun.gi b/hpcgap/lib/ratfun.gi index 6561ced599..0c89137d78 100644 --- a/hpcgap/lib/ratfun.gi +++ b/hpcgap/lib/ratfun.gi @@ -249,6 +249,26 @@ function(o) fi; end); +InstallOtherMethod(IsConstantRationalFunction,"fallback for non-ratfun",true, + [IsObject],0, +function(o) + if IsRationalFunction(o) then + TryNextMethod(); + else + return false; + fi; +end); + +InstallOtherMethod(IsUnivariateRationalFunction,"fallback for non-ratfun",true, + [IsObject],0, +function(o) + if IsRationalFunction(o) then + TryNextMethod(); + else + return false; + fi; +end); + ############################################################################# ## #M ExtRepPolynomialRatFun() @@ -1031,6 +1051,19 @@ function(r, c) return ProdCoefRatfun(c,r); end); +InstallMethod( \*, "ratfun * rat", true, + [ IsPolynomialFunction, IsRat ],-RankFilter(IsRat), +function( left, right ) + return left * (right*FamilyObj(left)!.oneCoefficient); +end ); + +InstallMethod( \*, "rat * ratfun ", true, + [ IsRat, IsPolynomialFunction], -RankFilter(IsRat), +function( left, right ) + return (left*FamilyObj(right)!.oneCoefficient) * right; +end); + + ############################################################################# ## #M + diff --git a/lib/ratfun.gd b/lib/ratfun.gd index cfe4d9f1e7..39ac3ce1dd 100644 --- a/lib/ratfun.gd +++ b/lib/ratfun.gd @@ -1576,7 +1576,7 @@ DeclareGlobalFunction("GcdCoeffs"); ## gap> UnivariatenessTestRationalFunction( (-6*y^2+y^3) / (y+1) ); ## [ true, 2, false, [ [ -6, 1 ], [ 1, 1 ], 2 ] ] ## gap> UnivariatenessTestRationalFunction( (-6*y^2+y^3) / (x+1)); -## [ fail, fail, fail, fail ] +## [ false, fail, false, fail ] ## gap> UnivariatenessTestRationalFunction( ((y+2)*(x+1)) / ((y-1)*(x+1)) ); ## [ fail, fail, fail, fail ] ## ]]> diff --git a/lib/ratfun.gi b/lib/ratfun.gi index 9ac8b0dc65..5f8e66bb83 100644 --- a/lib/ratfun.gi +++ b/lib/ratfun.gi @@ -243,6 +243,26 @@ function(o) fi; end); +InstallOtherMethod(IsConstantRationalFunction,"fallback for non-ratfun",true, + [IsObject],0, +function(o) + if IsRationalFunction(o) then + TryNextMethod(); + else + return false; + fi; +end); + +InstallOtherMethod(IsUnivariateRationalFunction,"fallback for non-ratfun",true, + [IsObject],0, +function(o) + if IsRationalFunction(o) then + TryNextMethod(); + else + return false; + fi; +end); + ############################################################################# ## #M ExtRepPolynomialRatFun() @@ -1025,6 +1045,19 @@ function(r, c) return ProdCoefRatfun(c,r); end); +InstallMethod( \*, "ratfun * rat", true, + [ IsPolynomialFunction, IsRat ],-RankFilter(IsRat), +function( left, right ) + return left * (right*FamilyObj(left)!.oneCoefficient); +end ); + +InstallMethod( \*, "rat * ratfun ", true, + [ IsRat, IsPolynomialFunction], -RankFilter(IsRat), +function( left, right ) + return (left*FamilyObj(right)!.oneCoefficient) * right; +end); + + ############################################################################# ## #M + diff --git a/lib/ratfun1.gi b/lib/ratfun1.gi index 6e7ad688aa..85891fed6c 100644 --- a/lib/ratfun1.gi +++ b/lib/ratfun1.gi @@ -86,6 +86,17 @@ local coefs, ind, extrep, i, shift,fam; end; +INDETS_POLY_EXTREP:=function(extrep) +local indets, i, j; + indets:=[]; + for i in [1,3..Length(extrep)-1] do + for j in [1,3..Length(extrep[i])-1] do + AddSet(indets, extrep[i][j]); + od; + od; + return indets; +end; + UNIVARTEST_RATFUN:=function(f) local fam,notuniv,cannot,num,den,hasden,indn,col,dcol,val,i,j,nud,pos; fam:=FamilyObj(f); @@ -104,6 +115,14 @@ local fam,notuniv,cannot,num,den,hasden,indn,col,dcol,val,i,j,nud,pos; den := ExtRepDenominatorRatFun(f); fi; + # if the symmetric difference of the indeterminates of the numerator and + # denominator contains more than one element, can't be univariate + i:=INDETS_POLY_EXTREP(num); + j:=INDETS_POLY_EXTREP(den); + if Size(Union(i,j)) > Size(Intersection(i,j))+1 then + return notuniv; + fi; + if Length(den[1])> 0 then # try a GCD cancellation i:=TryGcdCancelExtRepPolynomials(fam,num,den); diff --git a/tst/testinstall/ratfun.tst b/tst/testinstall/ratfun.tst index cfc94f2c2e..54e2300115 100644 --- a/tst/testinstall/ratfun.tst +++ b/tst/testinstall/ratfun.tst @@ -14,24 +14,84 @@ gap> u:=Indeterminate(Rationals,101);; gap> SetName(u,"u");; # -gap> p0:=0*t^0;; -gap> p1:=p0+0*t^0;; -gap> p2:=p0+1*t^0;; -gap> q0:=0;; -gap> q1:=q0+0*t^0;; -gap> q2:=q0+1*t^0;; -gap> List([p1,p2,q1,q2],x->IsPolynomial(x)); -[ true, true, true, true ] -gap> List([p1,p2,q1,q2],x->IsRat(x)); -[ false, false, false, false ] -gap> Value(p1,1); +# test basic properties +# +gap> data := [ 0*t, t^0, t, t+1, 1/t, 1/(t+1), t+u, t/u, t/(u+1), 0, 1/2 ]; +[ 0, 1, t, t+1, t^-1, (1)/(t+1), t+u, t/u, t/(u+1), 0, 1/2 ] +gap> List(data, IsRat); +[ false, false, false, false, false, false, false, false, false, true, true ] +gap> List(data, IsRationalFunction); +[ true, true, true, true, true, true, true, true, true, false, false ] +gap> List(data, IsConstantRationalFunction); +[ true, true, false, false, false, false, false, false, false, false, false ] +gap> List(data, IsPolynomial); +[ true, true, true, true, false, false, true, false, false, false, false ] +gap> List(data, IsUnivariatePolynomial); +[ true, true, true, true, false, false, false, false, false, false, false ] +gap> List(data, IsUnivariateRationalFunction); +[ true, true, true, true, true, true, false, false, false, false, false ] +gap> List(data, IsLaurentPolynomial); +[ true, true, true, true, true, false, false, false, false, false, false ] + +# +# arithmetics +# + +# multiplication +gap> List(data, x -> x * Zero(t)); +[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] +gap> ForAll(last,IsUnivariatePolynomial and IsZero); +true +gap> List(data, x -> Zero(t) * x); +[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] +gap> ForAll(last,IsUnivariatePolynomial and IsZero); +true +gap> List(data, x -> One(t) * x); +[ 0, 1, t, t+1, t^-1, (1)/(t+1), t+u, t/u, t/(u+1), 0, 1/2 ] +gap> last = data*t^0; +true +gap> List(data, x -> x * One(t)); +[ 0, 1, t, t+1, t^-1, (1)/(t+1), t+u, t/u, t/(u+1), 0, 1/2 ] +gap> last = data*t^0; +true + +# addition +gap> List(data, x -> x + Zero(t)); +[ 0, 1, t, t+1, t^-1, (1)/(t+1), t+u, t/u, t/(u+1), 0, 1/2 ] +gap> last = data*t^0; +true +gap> List(data, x -> Zero(t) + x); +[ 0, 1, t, t+1, t^-1, (1)/(t+1), t+u, t/u, t/(u+1), 0, 1/2 ] +gap> last = data*t^0; +true + +# commutative +gap> SetX(data, data, {x,y} -> x*y = y*x); +[ true ] +gap> SetX(data, data, {x,y} -> x+y = y+x); +[ true ] + +# associative +gap> SetX(data, data, data, {x,y,z} -> (x*y)*z = x*(y*z)); +[ true ] +gap> SetX(data, data, data, {x,y,z} -> (x+y)+z = x+(y+z)); +[ true ] + +# distributive +gap> SetX(data, data, data, {x,y,z} -> (x+y)*z = x*z+y*z); +[ true ] + +# +gap> Value(0*t,1); 0 -gap> Value(p2,1); +gap> Value(t^0,1); 1 -gap> Value(q1,1); -0 -gap> Value(q2,-1); +gap> Value(t^0,-1); 1 +gap> Value(t,-1); +-1 + +# gap> y1:=Indeterminate(Rationals,1);; gap> y2:=Indeterminate(Rationals,2);; gap> y3:=Indeterminate(Rationals,3);; @@ -71,7 +131,3 @@ t^8*u-u # gap> STOP_TEST( "ratfun.tst", 1); - -############################################################################# -## -#E diff --git a/tst/testinstall/ratfun_gf5.tst b/tst/testinstall/ratfun_gf5.tst new file mode 100644 index 0000000000..b5ced66d8f --- /dev/null +++ b/tst/testinstall/ratfun_gf5.tst @@ -0,0 +1,124 @@ +############################################################################# +## +#W ratfun.tst GAP Tests Alexander Hulpke +## +## +#Y (C) 1998 School Math. and Comp. Sci., University of St Andrews, Scotland +## +gap> START_TEST("ratfun_gf5.tst"); + +# +gap> t:=Indeterminate(GF(5),100);; +gap> SetName(t,"t");; +gap> u:=Indeterminate(GF(5),101);; +gap> SetName(u,"u");; + +# +# test basic properties +# +gap> data := [ 0*t, t^0, t, t+1, 1/t, 1/(t+1), t+u, t/u, t/(u+1), 0, 1/2 ];; +gap> List(data, IsRat); +[ false, false, false, false, false, false, false, false, false, true, true ] +gap> List(data, IsRationalFunction); +[ true, true, true, true, true, true, true, true, true, false, false ] +gap> List(data, IsConstantRationalFunction); +[ true, true, false, false, false, false, false, false, false, false, false ] +gap> List(data, IsPolynomial); +[ true, true, true, true, false, false, true, false, false, false, false ] +gap> List(data, IsUnivariatePolynomial); +[ true, true, true, true, false, false, false, false, false, false, false ] +gap> List(data, IsUnivariateRationalFunction); +[ true, true, true, true, true, true, false, false, false, false, false ] +gap> List(data, IsLaurentPolynomial); +[ true, true, true, true, true, false, false, false, false, false, false ] + +# +# arithmetics +# + +# multiplication +gap> ForAll(List(data, x -> x * Zero(t)), IsUnivariatePolynomial and IsZero); +true +gap> ForAll(List(data, x -> Zero(t) * x), IsUnivariatePolynomial and IsZero); +true +gap> ForAll(List(data, x -> One(t) * x) - data, IsUnivariatePolynomial and IsZero); +true +gap> ForAll(List(data, x -> x * One(t)) - data, IsUnivariatePolynomial and IsZero); +true + +# addition +gap> ForAll(List(data, x -> Zero(t) + x) - data, IsUnivariatePolynomial and IsZero); +true +gap> ForAll(List(data, x -> x + Zero(t)) - data, IsUnivariatePolynomial and IsZero); +true + +# commutative +gap> SetX(data, data, {x,y} -> x*y = y*x); +[ true ] +gap> SetX(data, data, {x,y} -> x+y = y+x); +[ true ] + +# associative +gap> SetX(data, data, data, {x,y,z} -> (x*y)*z = x*(y*z)); +[ true ] +gap> SetX(data, data, data, {x,y,z} -> (x+y)+z = x+(y+z)); +[ true ] + +# distributive +gap> SetX(data, data, data, {x,y,z} -> (x+y)*z = x*z+y*z); +[ true ] + +# +gap> Value(0*t,1); +0 +gap> Value(t^0,1); +Z(5)^0 +gap> Value(t^0,-1); +Z(5)^0 +gap> Value(t,-1); +Z(5)^2 + +# +gap> y1:=Indeterminate(Rationals,1);; +gap> y2:=Indeterminate(Rationals,2);; +gap> y3:=Indeterminate(Rationals,3);; +gap> mat:=[[y1,1,0],[y2,y1,1],[y3,y2,y1]];; +gap> det:=DeterminantMat(mat*y1^0);; +gap> Value(det,[y1,y2,y3],[1,-5,1]); +12 +gap> 1/( y1*y2 ); +1/(x_1*x_2) + +# +gap> Factors(t^24-1); +[ t+Z(5)^0, t+Z(5), t-Z(5)^0, t+Z(5)^3, t^2+Z(5), t^2+Z(5)^3, t^2+t+Z(5)^0, + t^2+t+Z(5), t^2+Z(5)*t-Z(5)^0, t^2+Z(5)*t+Z(5)^3, t^2-t+Z(5)^0, t^2-t+Z(5), + t^2+Z(5)^3*t-Z(5)^0, t^2+Z(5)^3*t+Z(5)^3 ] +gap> (t^24-1)/(t^16-1); +(t^16+t^8+Z(5)^0)/(t^8+Z(5)^0) +gap> (t^24-1)/(t^-16-1); +(t^32+t^24+t^16)/(-t^8-Z(5)^0) + +# +# multivariate +# +gap> (t^24-u^2)/(t^16-u^4); +(t^24-u^2)/(t^16-u^4) +gap> f:=u*(t^24-1);; g:=u^2*(t^16-1);; +gap> f/g; +(t^24*u-u)/(t^16*u^2-u^2) +gap> Factors(f); +[ u, t+Z(5)^0, t+Z(5), t-Z(5)^0, t+Z(5)^3, t^2+Z(5), t^2+Z(5)^3, + t^2+t+Z(5)^0, t^2+t+Z(5), t^2+Z(5)*t-Z(5)^0, t^2+Z(5)*t+Z(5)^3, + t^2-t+Z(5)^0, t^2-t+Z(5), t^2+Z(5)^3*t-Z(5)^0, t^2+Z(5)^3*t+Z(5)^3 ] +gap> Factors(t^4-u^4); +[ t+u, t+Z(5)*u, t-u, t+Z(5)^3*u ] + +# multivariate gcd +gap> Gcd(DefaultRing(f),f,g); +t^8*u-u +gap> Gcd(f,g); +t^8*u-u + +# +gap> STOP_TEST( "ratfun_gf5.tst", 1);