Sindbad~EG File Manager
/* M. Beeson, for Mathpert
Rational function arithmetic.
Used for graph-range setting and singularities calculations.
*/
/* Original date 11.10.96
Code last modified 4.18.97
Last modified 1.29.98
3.20.06 removed include heap.h as it's indirectly included from globals.h
*/
#include <assert.h>
#include <math.h>
#include "globals.h"
#include "ops.h"
#include "probtype.h"
#include "polynoms.h"
#include "order.h"
#include "cancel.h"
#include "algaux.h"
#include "simpsums.h"
#include "eqn.h"
#include "prover.h" /* noccurs */
#include "reset.h" /* save_and_reset */
#include "pvalaux.h" /* content_factor */
#include "polyquo.h"
#define MAXEXP 12 /* maximum exponent to be expanded */
#define UNITPOLY(p) (ARITY(p) == 1 && ONE(ARG(0,p)))
/*__________________________________________________________________________*/
int add_polyquos(POLYnomial p, POLYnomial q, POLYnomial r, POLYnomial s, POLYnomial *u, POLYnomial *v)
/* form the sum p/q + r/s and reduce it to form u/v where u and v are
POLYnomials with unit gcd. Return 0 for success, 1 for failure.
*/
{ POLYnomial g = polynomial_gcd(q,s);
POLYnomial trash,a,b,soverg,qoverg,gcd,z1,z2;
term cc,dd;
int err;
/* answer is (p(s/g) + r(q/g))/ (qs/g) */
/* unless that reduces further by cancelling out a common factor after
the addition. */
if(FUNCTOR(g) == ILLEGAL)
{ /* out of space in polynomial_gcd */
return 1;
}
if(UNITPOLY(g))
{ soverg = s;
cc = one;
}
else
pseudodiv(s,g,&soverg,&trash,&cc); /* soverg * g = s * cc */
if(UNITPOLY(q))
*v = soverg;
else if(UNITPOLY(soverg))
*v = q;
else
{ err = polymult(q,soverg,v);
if(err)
return 1;
}
if(UNITPOLY(p))
a = soverg;
else if(UNITPOLY(soverg))
a = p;
else
{ err = polymult(p,soverg,&a);
if(err)
return 1;
}
if(UNITPOLY(g))
{ qoverg = q;
dd = one;
}
else
pseudodiv(q,g,&qoverg,&trash,&dd);
err = polymult(r,qoverg,&b);
if(err)
return 1;
/* Now b needs adjusting by a factor to account for cc and dd */
/* This factor is cc / dd */
/* Instead though we multiply the denom and a by the dd factor
and b by the cc factor */
if(!ONE(cc))
b = polymultscalar(cc,b);
if(!ONE(dd))
{ a = polymultscalar(dd,a);
*v = polymultscalar(dd,*v);
}
*u = polyadd(a,b);
gcd = polynomial_gcd(*u,*v);
if(ARITY(gcd) > 1)
{ pseudodiv(*u,gcd,&z1,&trash,&cc);
pseudodiv(*v,gcd,&z2,&trash,&dd);
/* Now adjust for cc and dd as above */
if(!ONE(dd))
*u = polymultscalar(dd,z1);
else
*u = z1;
if(!ONE(cc))
*v = polymultscalar(cc,z2);
else
*v = z2;
}
return 0;
}
/*__________________________________________________________________________*/
POLYnomial polymultscalar(term c, POLYnomial u)
/* return cu */
{ int i;
unsigned short n = ARITY(u);
term r;
POLYnomial ans = make_term(POLY,n);
for(i=0;i<n;i++)
{ polyval(product(c,ARG(i,u)),&r);
ARGREP(ans,i,r);
}
return ans;
}
/*__________________________________________________________________________*/
int make_polyquo(term t, term x, POLYnomial *num, POLYnomial *denom)
/* Write t(x) as a quotient of polynomials, returning the
numerator and denominator in *num and *denom, in POLYnomial form,
and returning 0 for success. Return 1 for failure, in which
case *num and *denom can be garbage.
*/
{ int i,err;
POLYnomial p,q,r,s,u,v,g1,g2,temp,trash;
term cc,dd;
long exp;
unsigned short f = FUNCTOR(t);
unsigned short n = ARITY(t);
err = makepoly(t,x,num);
if(!err)
{ *denom = make_term(POLY,1);
ARGREP(*denom,0,one);
return 0; /* it was a polynomial */
}
switch(f)
{ case '-':
err = make_polyquo(ARG(0,t),x,&p,&q);
if(!err)
{ *num = polyneg(p);
*denom = q;
return 0;
}
return 1;
case '*':
err = make_polyquo(ARG(0,t),x,&p,&q);
if(err)
return 1;
for(i=1;i<n;i++)
{ if(!contains(ARG(i,t),FUNCTOR(x)))
{ p = polymultscalar(ARG(i,t),p);
continue;
}
err = make_polyquo(ARG(i,t),x,&r,&s);
if(err)
return 1;
err = polymult(p,r,&u);
if(err)
return 1;
err = polymult(q,s,&v);
if(err)
return 1;
/* But now there may be cancellations to consider */
g1 = polynomial_gcd(p,s);
g2 = polynomial_gcd(q,r);
if(UNITPOLY(g1) && UNITPOLY(g2))
{ p = u;
q = v;
continue;
}
if(!UNITPOLY(g1))
{ /* replace p and s by p/g1 and s/g1 respectively */
pseudodiv(p,g1,&temp,&trash,&cc);
p = temp;
pseudodiv(s,g1,&temp,&trash,&dd);
s = temp;
if(!ONE(cc))
s = polymultscalar(make_power(cc,make_int(ARITY(p)-ARITY(g1)+1)),s);
if(!ONE(dd))
p = polymultscalar(make_power(dd,make_int(ARITY(s)-ARITY(g1)+1)),p);
}
if(!UNITPOLY(g2))
{ /* replace q and r by q/g2 and r/g2 respectively */
pseudodiv(q,g2,&temp,&trash,&cc);
q = temp;
pseudodiv(r,g2,&temp,&trash,&dd);
r = temp;
if(!ONE(cc))
r = polymultscalar(make_power(cc,make_int(ARITY(p)-ARITY(g1)+1)),r);
if(!ONE(dd))
q = polymultscalar(make_power(dd,make_int(ARITY(s)-ARITY(g1)+1)),q);
}
}
*num = p;
*denom = q;
return 0;
case '+':
err = make_polyquo(ARG(0,t),x,&p,&q);
if(err)
return 1;
for(i=1;i<n;i++)
{ err = make_polyquo(ARG(i,t),x,&r,&s);
if(err)
return 1;
err = add_polyquos(p,q,r,s,&u,&v);
if(err)
return 1;
p = u;
q = v;
}
*num = p;
*denom = q;
return 0;
case '^':
if(NEGATIVE(ARG(1,t)) && ISINTEGER(ARG(0,ARG(1,t))))
{ exp = INTDATA(ARG(0,ARG(1,t)));
if(exp > MAXEXP)
return 1;
err = make_polyquo(ARG(0,t),x,&p,&q);
if(err)
return 1;
if(exp == 1)
{ *num = q;
*denom = p;
return 0;
}
*num = polyexp(q,exp);
*denom = polyexp(p,exp);
return 0;
}
else if(ISINTEGER(ARG(1,t)))
exp = INTDATA(ARG(1,t));
else
return 1;
if(exp > MAXEXP)
return 1;
err = make_polyquo(ARG(0,t),x,&p,&q);
if(err)
return 1;
*num = polyexp(p,exp);
*denom = polyexp(q,exp);
return 0;
case '/':
err = cancel(ARG(0,t),ARG(1,t),&p,&q);
if(!err) /* example: 6x^2y^6/6x^2y^4 */
{ if(FRACTION(q))
t = q;
else
return make_polyquo(q,x,num,denom);
}
err = make_polyquo(ARG(0,t),x,&p,&q);
if(err)
return 1;
err = make_polyquo(ARG(1,t),x,&r,&s);
if(err)
return 1;
if(UNITPOLY(s))
*num = p;
else
{ err = polymult(p,s,num);
if(err)
return 1;
}
if(UNITPOLY(q))
*denom = r;
else
{ err = polymult(q,r,denom);
if(err)
return 1;
}
g1 = polynomial_gcd(*num,*denom);
if(ARITY(g1) > 1)
{ /* cancel the gcd from num and denom */
pseudodiv(*num,g1,&p,&r,&cc);
if(ARITY(r) > 1 || !ZERO(ARG(0,r)))
assert(0);
pseudodiv(*denom,g1,&q,&r,&dd);
if(ARITY(r) > 1 || !ZERO(ARG(0,r)))
assert(0);
if(ONE(cc))
*denom = q;
else
*denom = polymultscalar(make_power(cc,make_int(ARITY(*num)-ARITY(g1)+1)),q);
if(ONE(dd))
*num = p;
else
*num = polymultscalar(make_power(dd,make_int(ARITY(*denom)-ARITY(g1)+1)),p);
}
return 0;
}
return 1;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists