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.