Rational functions in GAP

We give some examples of GAP's external representation of of rational functions and polynomials. Also, we give an example of finding the leading monomial.

First, introduce some variables, say x and y.

x:=Indeterminate(Rationals,"x");
y:=Indeterminate(Rationals,"y");
GAP represents rational functions in a given family using lists. First, the family must be defined, for example:
fam1:=RationalFunctionsFamily(FamilyObj(1));;
fam2:=RationalFunctionsFamily(FamilyObj(4/5));;
fam3:=RationalFunctionsFamily(FamilyObj(Z(13)));;
The argument "1" (or "4/5", "Z(13)") plays the role of defining the characteristic of the ground field (any element of the rationals indicates characteristic 0, Z(13) indicates characteristic 13). fam1 and fam2 are the same GAP family and may be regarded roughly speaking as the set of rational functions in arbitrarily many variables (even though only x,y have been defined at this point). The variables defined so far can be obtained from the command fam1!.namesIndets; (which returns [ "x", "y" ]). In these families, a polynomial or rational function is specified by a list of numbers. These numbers determine the variable, the exponent of that variable, and the coefficient. For example,
f1:=PolynomialByExtRep(fam1,[[1,2],-4,[1,-5,2,1],3]);
determines the polynomial 3*x^-5*y-4*x^2,
f2:=PolynomialByExtRep(fam1,[[1,-5,2,1],3,[1,2],-4]);
determines the polynomial -4*x^2+3*x^-5*y (note that: f1=f2; returns false since these are entered in different order!), and
f3:=PolynomialByExtRep(fam2,[[1,2],-4*Z(13)^0,[1,-5,2,1],3*Z(13)^0]);
determines Z(13)^8*x^2+Z(13)^4*x^-5*y. GAP does not know much about these functions: NamesOfComponents(f1); returns [ "ExtRepPolynomialRatFun" ]. We can add the component f1!.groundfield:="Rationals"; so that for the command NamesOfComponents(f1); GAP returns [ "ExtRepPolynomialRatFun", "groundfield" ]. In fact, since f1 has been defined "illegally" (a negative exponent is allowed in the syntax but ``illegal'' from the point of view of the algorithms used to compute with rational functions), GAP thinks it is a polynomial(!):
KnownPropertiesOfObject(f1);
#[ "CanEasilyCompareElements", "CanEasilySortElements", "IsPolynomial" ]
IsPolynomial(f1);
#true

Note that usual addition and division works fine for sums of monomials with non-negative exponents:

p1:=PolynomialByExtRep(fam1,[[1,2],-4,[1,5,2,1],3]);
p2:=PolynomialByExtRep(fam2,[[1,2,2,1],3,[1,2,2,2],1]);
p:=p1*p2;
d:=PolynomialByExtRep(fam1,ExtRepDenominatorRatFun(p1/p+p2/p));
d/p2 = p1;
#true
d/p1 = p2;
#true
The command
q:=RationalFunctionByExtRep(fam1,[ [ 1, 1, 2, 7 ], -1, [ 1, 4, 2, 5 ], 3 ],[[1,2],4,[2,-3],4]);
determines the rational function:
(-x*y^7+3*x^4*y^5)/(4*x^2+4*y^-3)
(The ordering of the terms as printed on the screen does not appear to be the same for different occurrances, so you may see for example (3*x^4*y^5-x*y^7)/(4*y^-3+4*x^2) instead.) Conversely, the external representation of the polynomial
f:=3*x^4*y^5-x*y^7;
can be determined by
Xf:=ExtRepPolynomialRatFun(f);
which returns: [ [ 1, 1, 2, 7 ], -1, [ 1, 4, 2, 5 ], 3 ], and
ExtRepPolynomialRatFun(p2);
returns: [ [ 1, 2, 2, 1 ], 3, [ 1, 2, 2, 2 ], 1 ]. There is a similar command for rational functions:
ExtRepNumeratorRatFun(q);
returns: [ [ 1, 1, 2, 7 ], -1, [ 1, 4, 2, 5 ], 3 ], and
ExtRepDenominatorRatFun(q);
returns: [ [ 1, 2 ], 4, [ 2, -3 ], 4 ].

What is the coefficient of the leading term of this polynomial in the total degree monomial ordering? The commands

i:=LeadingMonomialPosExtRep(fam1,Xf,MonomialTotalDegreeLess);
and
ord:=MonomialGrlexOrdering([x,y]);
my_order:=MonomialExtrepComparisonFun(ord);
i:=LeadingMonomialPosExtRep(fam1,Xf,my_order);
both return the answer, 3. The following commands read off the leading term:
Xg:=[Xf[i],Xf[i+1]];;
PolynomialByExtRep(fam1,Xg);
namely: 3*x^4*y^5. Consider the polynomial rings R1 and R2 defined by
R1:=PolynomialRing(Rationals,["x","y"]);
R2:=PolynomialRing(Rationals,["a","b"]);
The command Value allows one to substitute. This is all GAP has to implement a polynomial ring homomorphism. For example, if
x:=IndeterminatesOfPolynomialRing(R1)[1];
y:=IndeterminatesOfPolynomialRing(R1)[2];
a:=IndeterminatesOfPolynomialRing(R2)[1];
b:=IndeterminatesOfPolynomialRing(R2)[2];
f:=3*x^4*y^5-x*y^7;
then the command Value(f,[x,y],[a,b]); yields 3*a^4*b^5-a*b^7 and g:=Value(f,[x,y],[a+b,b^2]); yields -a*b^14-b^15+3*a^4*b^10+12*a^3*b^11+18*a^2*b^12+12*a*b^13+3*b^14. Here's a program to determine how many monomial terms a sum of monomials has:
length_rat_fcn:=function(f)
 local i,j,e,s,m,a;
 e:=ExtRepPolynomialRatFun(f);
 s:=String(e);
 i:=-1;
 for j in [1..Length(s)] do
   if s[j]='[' then i:=i+1; fi;
 od; 
return(i);
end;
For example, length_rat_fcn(g); returns 7.

Here's the denominator of a rational function q:

denom_q:=PolynomialByExtRep(fam1,ExtRepDenominatorRatFun(q));
One can also use DenominatorOfRationalFunction. Here's the numerator of a rational function q:
numer_q:=PolynomialByExtRep(fam1,ExtRepNumeratorRatFun(q));
One can also use NumeratorOfRationalFunction.

Adding any two rational functions is not known to GAP. For example, if q is

RationalFunctionByExtRep(fam1,[[1,1,2,7],-1,[1,4,2,5],3],[[1,2],4,[2,-3],4]);
so q=(3x4y5-xy7)/(4y-3+4x2) (note: this is "illegal" since there is a negative exponent of y in the denominator), and if r is
RationalFunctionByExtRep(fam1,[[1,2,2,4],2,[1,4,2,3],-2],[[1,1],1,[2,1],3])
so r=(-2x4y3+2x2y4)/(3y+x), then GAP cannot compute q+r. This is because q is "illegal". To add two rational functions constructed in this way, the following works:
add_rational_functions:=function(r,q,fam)
local denom_r,denom_q,numer_q,numer_r,ext_num,ext_den,sum;
 denom_q:=PolynomialByExtRep(fam,ExtRepDenominatorRatFun(q));
 numer_q:=PolynomialByExtRep(fam,ExtRepNumeratorRatFun(q));
 denom_r:=PolynomialByExtRep(fam,ExtRepDenominatorRatFun(r));
 numer_r:=PolynomialByExtRep(fam,ExtRepNumeratorRatFun(r));
 ext_num:=ExtRepPolynomialRatFun(numer_r*denom_q+numer_q*denom_r);
 ext_den:=ExtRepPolynomialRatFun(denom_r*denom_q);
 sum:=RationalFunctionByExtRep(fam,ext_num,ext_den);
return(sum);
end;
For example,
x:=Indeterminate(Rationals,"x");
y:=Indeterminate(Rationals,"y");
fam:=RationalFunctionsFamily(FamilyObj(1));;
q:=RationalFunctionByExtRep(fam,[[1,1,2,7],-1,[1,4,2,5],3],[[1,2],4,[2,-3],4]);
r:=RationalFunctionByExtRep(fam,[[1,2,2,4],2,[1,4,2,3],-2],[[1,1],1,[2,1],3]); 
add_rational_functions(r,q,fam);
computes r+q correctly. However, if q was constructed "legally" as the quotient of two polynomials, then r+q; would work in GAP.

Finally, we give an algorithm to determine a common denominator.

INPUT: A list of rational functions, r1=q1/p1, r2=q2/p2, ..., rk=qk/pk (pi,qj polynomials in several variables).

OUTPUT: A common denominator d and polynomials s1, ..., sk satisfying r1=s1/d, r2=s2/d, ..., rk=sk/d.

common_denominator:=function(L)
local M,i,j,s,d,n,sum;
 n:=Length(L);
 sum:=Sum(L);
 s:=[];
 d:=DenominatorOfRationalFunction(sum);
 for i in [1..n] do
  s[i]:=(L[i]*d);
 od;
 M:=List([s,d]);
return(M);
end;
Here's an example:
a:=common_denominator([p1/p,p2/p]);
s:=a[1];
d:=a[2];
s[1]/d=p1/p;
s[2]/d=p2/p;
For the last two commands, GAP returns true.
Created 7-15-2004 by wdj. Last modified 7-26-2004.