Sindbad~EG File Manager
| Current Path : /home/beeson/ |
|
|
| Current File : //home/beeson/redrat.c |
/* automatic calculation of singularities
for use in Mathpert's grapher */
/* M. Beeson
2.16.92 original date
6.14.98 last modified;
3.28.00 replaced assert(0) with return 1 in reduce_to_rational
3.20.06 removed duplicate include polynoms.h
5.5.13 changed malloc.h to stdlib.h
8.18.23 added make_fraction at line 495
8.8.24 replaced math.h with sincos.h
*/
#include <assert.h>
#include <stdlib.h> /* alloca */
#include <sincos.h>
#include "globals.h"
#include "prover.h"
#include "polynoms.h"
#include "cancel.h"
#include "order.h"
#include "deriv.h"
#include "eqn.h"
#include "algaux.h"
#include "trigpoly.h"
#include "trigdom.h"
#include "reset.h"
#include "userfunc.h"
#include "sturm.h" /* nroots */
#include "pvalaux.h" /* obviously_positive */
#include "polyquo.h" /* make_polyquo */
#include "psubst.h"
#include "islinear.h"
#include "factor.h" /* sqrt_aux */
#include "deval.h"
#include "periodic.h" /* periodic_in */
#include "trigatr.h" /* trig_arctrig_singularities */
#include "trigsimp.h" /* trigsimp2 */
#include "ops.h"
#include "trig.h" /* TRIGFUNCTOR */
#include "maxsub.h" /* maximal_sub */
#include "nperiod.h" /* near_periodic, near_periodic_singularities */
#include "singular.h"
#include "simpprod.h"
#include "redrat.h"
#include "sqrtaux.h" /* sqrt_aux2 */
static int contains_rootexp(term t, term x);
static int algebraic(term t,term x,term *def);
/*________________________________________________________________________*/
static int algebraic(term t,term x,term *def)
/* If t is a rational function of x and a SQRT of a polynomial of x,
return the radical in def and return 0 for success. Return 1
for failure. If called with *def an ILLEGAL term, it searches
for a radical and puts *def equal to the first radical
containing x which is encountered.
Fractional powers are acceptable but *def is always returned as a
SQRT or ROOT. If a 'radical' in the form v^(2/3) is encountered,
it treats that the same as v^(1/3) or root(3,v), so *def is set to root(3,v).
If *def is not ILLEGAL, it just looks for that particular radical;
if a different one is encountered, it fails. If there is no SQRT containing
x, and t is a rational function, then 0 will be returned
without ever instantiating *def, which will still be ILLEGAL.
*/
{ int i,err;
unsigned short n,f;
term index,u,temp;
POLYnomial p;
if(ATOMIC(t))
return 0;
f = FUNCTOR(t);
n = ARITY(t);
if( ( f == SQRT ||
(f == '^' && RATIONALP(ARG(1,t)) && equals(ARG(1,ARG(1,t)),two))
) &&
contains(ARG(0,t),FUNCTOR(x))
)
{ u = ARG(0,t);
index = two;
if(FUNCTOR(*def) == ILLEGAL)
{ err = makepoly(u,x,&p);
if(err)
return 1;
*def = make_sqrt(u);
return 0;
}
else
{ if(equals(t,*def))
return 0;
if(FUNCTOR(*def) == ROOT)
return 1;
polyval(sum(ARG(0,*def),tnegate(u)),&temp);
if(ZERO(temp))
return 0;
return 1;
}
}
if(
(f == ROOT && contains(ARG(1,t),FUNCTOR(x))) ||
(f == '^' && RATIONALP(ARG(1,t)) && ISINTEGER(ARG(1,ARG(1,t))) && contains(ARG(0,t),FUNCTOR(x)))
)
{ u = f == ROOT ? ARG(1,t): ARG(0,t);
if(FUNCTOR(u) == '^' && INTEGERP(ARG(1,u)))
u = ARG(0,u);
index = f == ROOT ? ARG(0,t) : ARG(1,ARG(1,t));
if(FUNCTOR(*def) == ILLEGAL)
{ err = makepoly(u,x,&p);
if(err)
return 1;
*def = equals(index,two) ? make_sqrt(u) : make_root(index,u);
return 0;
}
else
{ if(equals(t,*def))
return 0;
if(FUNCTOR(*def) == SQRT)
return 1;
polyval(sum(ARG(1,*def),tnegate(u)),&temp);
if(ZERO(temp))
return 0;
return 1;
}
}
if(f == '^')
{ if(contains(ARG(1,t),FUNCTOR(x)))
return 1;
return algebraic(ARG(0,t),x,def);
}
if(f != '+' && f != '-' && f != '*' && f != '/')
return 1;
for(i=0;i<n;i++)
{ err = algebraic(ARG(i,t),x,def);
if(err)
return 1;
}
return 0;
}
/*__________________________________________________________________________*/
static int contains_rootexp(term t, term x)
/* return 1 if t contains a root or sqrt or fractional exponent
containing the atom x. Return 0 otherwise.
*/
{ unsigned short n,f;
int i;
if(ATOMIC(t))
return 0;
f = FUNCTOR(t);
if(f == SQRT || (f == '^' && SIGNEDFRACTION(ARG(1,t))) || f == ROOT)
return contains(t,FUNCTOR(x));
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_rootexp(ARG(i,t),x))
return 1;
}
return 0;
}
/*______________________________________________________________________*/
int reduce_to_rational(term t, term x, term *ans, term *u, term *xofu)
/* If possible, find a substitution which reduces t to
a rational function of u. In particular, if t is a rational function
of x and sqrt(ax+b)), then x = (1/a)u^2-b/a will do, since then u = sqrt(ax+b).
Presumes x is the eigenvariable.
If it succeeds, this function has introduced a new variable.
Return in *xofu the equation which gives x as a function of u.
The new variable is returned in *u.
*ans is t written as a rational function of *u.
For example, if *def is sqrt(x-2), then *xofu will be x = u^2 + 2.
Note: this amounts to the following: find a rational parametrization
of the algebraic curve p(x,y) = 0, where p is the polynomial satisfied by
the algebraic function def such that t is a rational function of x and def(x),
i.e. p(x,def) = 0. So in the example where def = sqrt(x-2), we
have p(x,y) = y^2 + 2 - x, which is parametrized by y = u, x = u^2 + 2.
Return 0 or 2 for success, 1 for failure. Return value 2 means that
the substitution has introduced new singularities at u = 1 and -1,
in other words that the parameter domain in u is (-1,1).
Return value 3 indicates that the domain will contain only isolated
points because there is a sqrt(-u^2) term.
*/
{ int err,err2,nvariables;
int savenvariables;
int saveeigenindex;
term temp,temp2,v,index,q,r,z,zz,def,yofu,oneroot,otherroot,almost;
int signa, signc;
POLYnomial p;
SETFUNCTOR(def,ILLEGAL,0);
err = algebraic(t,x,&def);
if(err && FUNCTOR(def) != SQRT)
return 1;
if(err)
{ /* but algebraic did find a SQRT term before failing */
/* catch functions which contain two linear sqrts */
term ans1,wofu,w,xofw;
if(!is_linear_in(ARG(0,def),x))
return 1;
savenvariables = get_nvariables();
saveeigenindex = get_eigenindex();
w = getnewvar(t,"uvpqrstxyz");
if(FUNCTOR(w) == ILLEGAL)
return 1; /* too many variables already exist */
vaux(w);
psubst(w,def,t,&temp2);
polyval(temp2,&temp);
err = ssolve(equation(w,ARG(0,def)),x,&q);
if(err)
{ /* assert(0), since ARG(0,def) is linear in x */
set_eigenvariable(saveeigenindex);
set_nvariables(savenvariables);
return 1;
}
if(FUNCTOR(q) != '=' || !equals(x,ARG(0,q)) || contains(ARG(1,q),FUNCTOR(x)))
return 1; /* assert(0); */
subst(make_power(w,two),w,q,&r);
if(!contains(temp,FUNCTOR(x)) && rational_function(temp,w))
{ /* then we're done already, e.g. if there were two radicals and
one is a multiple of the other */
*ans = temp;
*u = w;
*xofu = r;
return 0;
}
subst(r,x,temp,&z);
/* If t was a rational function of sqrt(x-1) and sqrt(x-2) for example,
now sqrt(x-1) has become w and sqrt(x-2) has become sqrt(w^2-1),
which can be handled by the code below. So the following
recursive call will succeed. */
polyval(z,&zz);
err = reduce_to_rational(zz,w,&ans1,u,&wofu);
if(err==1)
{ set_nvariables(savenvariables);
set_eigenvariable(saveeigenindex);
return 1;
}
/* Now solve for x in terms of w */
err2 = ssolve(equation(w,ARG(0,def)),x,&q);
/* really w^2 = ARG(0,def), but below we substitute w^2 for w after solving */
if(err2)
{ /* assert(0), since ARG(0,def) is linear in x */
set_nvariables(savenvariables);
set_eigenvariable(saveeigenindex);
return 1;
}
subst(make_power(w,two),w,q,&xofw);
if(FUNCTOR(wofu) != '=' || !equals(ARG(0,wofu),w))
assert(0);
subst(ARG(1,wofu),w,xofw,xofu);
subst(ARG(1,wofu),w,ans1,&almost);
polyval(almost,ans);
/* Now get rid of the intermediate variable w */
nvariables = get_nvariables();
swapvars(nvariables-1,nvariables-2);
set_nvariables(nvariables-1);
/* and restore the original eigenvariable */
set_eigenvariable(saveeigenindex);
return err;
}
/* Now we're in the case where algebraic succeeded, i.e. t was a rational
function of x and a single radical */
if(FUNCTOR(def) == ILLEGAL)
return 1;
if(FUNCTOR(def) == SQRT)
{ v = ARG(0,def);
index = two;
}
else
{ v = ARG(1,def);
index = ARG(0,def);
}
if(is_linear_in(v,x))
{ savenvariables = get_nvariables();
*u = getnewvar(t,"uvpqrstxyz");
if(FUNCTOR(*u) == ILLEGAL)
return 1; /* too many variables already exist */
vaux(*u);
err = ssolve(equation(*u,v),x,xofu);
if(err)
{ set_nvariables(savenvariables);
return 1;
}
subst(make_power(*u,index),*u,ARG(1,*xofu),&q);
*xofu = equation(x,q);
subst(*u,def,t,&temp);
psubst(q,x,temp,&temp2);
polyval(temp2,ans);
if(contains(*ans,FUNCTOR(x)))
return 1;
if(contains_rootexp(*ans,x))
return 1; /* assert(0), but you never know... */
return 0;
}
err = makepoly(v,x,&p);
if(!err && ARITY(p) == 3)
{ /* sqrt(quadratic) can be handled by the Weierstrass substitution */
term a,b,c,sqrta,sqrtcovera,covera,sqrtc,addthis,newc;
a = ARG(2,p);
b = ARG(1,p);
c = ARG(0,p);
if(ZERO(b) && ZERO(c))
return 1; /* it's really a function of abs(x) and x, since abs(x) = sqrt(x^2) */
/* First determine the sign of a, or else fail if you can't */
if(obviously_positive(a))
signa = 1;
else if (obviously_negative(a))
signa = -1;
else if(!infer(lessthan(zero,a)))
signa = 1;
else if(!infer(lessthan(a,zero)))
signa = -1;
else
return 1;
if(signa == -1)
{ a = tnegate(a);
b = tnegate(b);
c = tnegate(c);
}
err = sqrt_aux2(a,&sqrta);
if(err)
sqrta = make_sqrt(a);
if(!ZERO(b))
{ /* we must complete the square first */
/* ax^2 + bx + c = (sqrt(a)x+(b/2sqrt(a))^2 + c-b^2/4a) */
polyval(make_fraction(b,product(two,sqrta)),&addthis);
polyval(sum(c,tnegate(make_fraction(make_power(b,two),product(four,a)))),&newc);
}
else
{ newc = c;
addthis = zero;
}
if(ZERO(newc))
{ /* what was under the quadratic is a perfect square, say u^2 */
/* u = sqrt(a) x + addthis, so x = (u - addthis)/sqrt(a) */
if(signa == -1)
return 3; /* only isolated points in the domain */
*u = getnewvar(t,"uvpqrstxyz");
if(FUNCTOR(*u) == ILLEGAL)
return 1; /* too many variables already exist */
vaux(*u);
yofu = *u;
subst(yofu,def,t,&almost);
if(ZERO(addthis))
oneroot = make_fraction(*u,sqrta);
else
oneroot = make_fraction(sum(*u, tnegate(addthis)),sqrta);
*xofu = equation(x,oneroot);
if(contains(almost,FUNCTOR(x)))
{ psubst(oneroot,x,almost,&temp2);
polyval(temp2,ans);
}
else
polyval(almost,ans);
return 0;
}
/* Now newc is not zero. Use a trig substitution followed by
the Weierstrass substitution. When
u = tan(theta/2), we have
cos theta = (1-u^2)/(u^2+1),
sin theta = 2u/(1+u^2), hence
tan theta = 2u/(1-u^2),
sec theta = (u^2+1)/(1-u^2)
*/
/* If signa was negative, then we're looking at sqrt(-(a(x+..)^2 + newc))
so newc better not be positive, or the function is undefined */
if(signa == -1)
{ if(!obviously_negative(newc))
return 1;
signc = -1;
}
else
{ if(obviously_positive(newc))
signc = 1;
else if(obviously_negative(newc))
{ signc = -1;
newc = tnegate(newc);
}
else if(!infer(lessthan(zero,newc)))
signc = 1;
else if(!infer(lessthan(newc,zero)))
signc = -1;
else
return 1;
}
if(signa == 1 && signc == 1)
{ /* Then (in the case b == 0)
ax^2 + c = c tan^2 theta + c
so sqrt(c) tan theta = sqrt(a) x
x = (sqrt c/a) tan theta = (sqrt c/a) (2 u / (1-u^2))
and *def = sqrt(ax^2 + c) = sqrt(c) sec^2 theta =
sqrt(c) ((u^2+1)^2)/(1-u^2)^2)
When b is not zero, we have instead
(sqrt(a)x + addthis) = sqrt(newc) tan theta = sqrt(newc) 2u/(1-u^2)
x = sqrt(newc/a) 2u/(1-u^2) - addthis/sqrt(a)
or x = -sqrt(newc/a) 2u/(1-u^2) - addthis/sqrt(a)
yofu is then sqrt(newc(tan^2 theta + 1)) = sqrt(newc) sec theta =
sqrt(newc) (u^2+1)/(1-u^2)
*/
*u = getnewvar(t,"uvpqrstxyz");
if(FUNCTOR(*u) == ILLEGAL)
return 1; /* too many variables already exist */
vaux(*u);
polyval(make_fraction(newc,a),&covera);
err = sqrt_aux2(covera,&sqrtcovera);
if(err)
sqrtcovera = make_sqrt(covera);
temp = make_fraction(product3(two,sqrtcovera,*u),sum(one,tnegate(make_power(*u,two))));
if(ZERO(b))
{ polyval(temp,&oneroot);
copy(tnegate(oneroot),&otherroot);
*xofu = or(equation(x,oneroot),equation(x,otherroot));
}
else
{ polyval(sum(temp,tnegate(make_fraction(addthis,sqrta))),&oneroot);
polyval(sum(tnegate(temp),tnegate(make_fraction(addthis,sqrta))),&otherroot);
*xofu = or(equation(x,oneroot),equation(x,otherroot));
}
err = sqrt_aux2(newc,&sqrtc);
if(err)
sqrtc = make_sqrt(newc);
yofu = make_fraction(
product(sqrtc,sum(make_power(*u,two),one)),
sum(one,tnegate(make_power(*u,two)))
);
psubst(yofu,def,t,&almost);
polyval(almost,ans);
if(contains(*ans,FUNCTOR(x)))
return 1;
return 2;
}
if(signa == 1 && signc == -1)
{ /* Then (in the case b == 0 )
ax^2 - c = c(sec^2 theta-1) = c tan^2 theta = c (2u/(u^2-1))^2
and ax^2 = c sec^2 theta
x = sqrt(c/a) sec theta = sqrt(c/a) (u^2+1)/(1-u^2)
When b is not zero, we have instead
sqrt(a) x + addthis = sqrt(newc) sec theta = sqrt(newc) (u^2+1)/(1-u^2)
x = sqrt(newc/a) (u^2+1)/(1-u^2) - addthis/sqrt(a)
yofu = sqrt(c) (2u/(1-u^2)) from the first line above.
*/
*u = getnewvar(t,"uvpqrstxyz");
if(FUNCTOR(*u) == ILLEGAL)
return 1; /* too many variables already exist */
vaux(*u);
polyval(make_fraction(newc,a),&covera);
err = sqrt_aux2(covera,&sqrtcovera);
if(err)
sqrtcovera = make_sqrt(covera);
temp = make_fraction(product(sqrtcovera,sum(make_power(*u,two),one)),
sum(one,tnegate(make_power(*u,two)))
);
if(ZERO(b))
{ polyval(temp,&oneroot);
copy(tnegate(oneroot),&otherroot);
*xofu = or(equation(x,oneroot),equation(x,otherroot));
}
else
{ polyval(sum(temp,tnegate(make_fraction(addthis,sqrta))),&oneroot);
polyval(sum(tnegate(temp),tnegate(make_fraction(addthis,sqrta))),&otherroot);
*xofu = or(equation(x,oneroot),equation(x,otherroot));
}
err = sqrt_aux2(newc,&sqrtc);
if(err)
sqrtc = make_sqrt(newc);
yofu = make_fraction(
product3(two,sqrtc,*u),
sum(one,tnegate(make_power(*u,two)))
);
psubst(yofu,def,t,&almost);
polyval(almost,ans);
if(contains(*ans,FUNCTOR(x)))
return 1;
return 2;
}
if(signa == -1)
{ /* Then (in the case b == 0 )
-( ax^2 - c) = c(1-sin^2 theta) = c cos^2 theta = c ((u^2-1)/(u^2+1))^2
and ax^2 = c sin^2 theta
x = sqrt(c/a) sin theta = sqrt(c/a) 2u/(1+u^2)
When b is not zero, we have instead
sqrt(a) x + addthis = sqrt(newc) sin theta = sqrt(newc) 2u/(u^2+1)
x = sqrt(newc/a) 2u/(u^2+1) - addthis/sqrt(a)
*/
*u = getnewvar(t,"uvpqrstxyz");
if(FUNCTOR(*u) == ILLEGAL)
return 1; /* too many variables already exist */
vaux(*u);
polyval(make_fraction(newc,a),&covera);
err = sqrt_aux2(covera,&sqrtcovera);
if(err)
sqrtcovera = make_sqrt(covera);
temp =make_fraction(product3(two,sqrtcovera,*u),sum(make_power(*u,two),one));
if(ZERO(b))
{ polyval(temp,&oneroot);
copy(tnegate(oneroot),&otherroot);
*xofu = or(equation(x,oneroot),equation(x,otherroot));
}
else
{ polyval(sum(temp,tnegate(make_fraction(addthis,sqrta))),&oneroot);polyval(sum(tnegate(temp),tnegate(make_fraction(addthis,sqrta))),&otherroot);
*xofu = or(equation(x,oneroot),equation(x,otherroot));
}
err = sqrt_aux2(newc,&sqrtc);
if(err)
sqrtc = make_sqrt(newc);
yofu = make_fraction(
product(sqrtc,sum(one,tnegate(make_power(*u,two)))),
sum(make_power(*u,two),one)
);
psubst(yofu,def,t,&almost);
polyval(almost,ans);
if(contains(*ans,FUNCTOR(x)))
return 1;
return 0;
}
}
return 1;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists