Sindbad~EG File Manager
| Current Path : /usr/home/beeson/ |
|
|
| Current File : //usr/home/beeson/domexp.c |
/* M. Beeson, for Mathpert.
Domain of a^b.
Original date 2.1.92
Last modified 8.14.98
8.8.24 replaced math.h with sincos.h
*/
#include <assert.h>
#include <sincos.h> // <math.h> without sincos
#include "globals.h"
#include "prover.h"
#include "dcomplex.h"
#include "cancel.h"
#include "deval.h"
#include "deriv.h"
#include "order.h"
#include "domain.h"
#include "algaux.h"
#include "trigdom.h"
#include "trigpoly.h"
#include "trig.h"
#include "pvalaux.h" /* isinteger, isodd, etc. */
#include "tdefn.h"
#include "domexp.h"
#include "cflags.h" /* get_currenttopic */
#include "binders.h"
static term domexp1(term a, term b);
static term domexp2(term a, term b);
/* The conditions for a power to be defined are complicated by the fact
that negative bases to rational powers with odd denominators are defined,
but other powers of negative bases are not. The exact conditions are:
a^num/den defined iff
and(
a defined,
or(b > 0, a !=0),
or(
and(numint, denint, (odd(den) or a � 0))
a > 0
)
)
If these conditions are implemented literally, they clutter up the
assumptions with unwieldy disjunctions that can never be verifed or used,
but just look ugly and sometimes run us out of space in manipulations.
In calculus, therefore, we ignore the possibility that some exponents
take rational values. The domain of x^x for example will come out x > 0,
rather than "x > 0 or x a negative rational with odd denominator".
You still will be able to evaluate numerically at x = -3 for example.
But in equation-solving, we don't want to do that, for we may miss some
solutions that way.
*/
/*____________________________________________________________________*/
term domexp(term a, term b)
/* return the domain of a^b calculated as described above */
{ int currenttopic = get_currenttopic();
if(CALCULUS_TOPIC(currenttopic))
return domexp2(a,b);
return domexp1(a,b);
}
/*________________________________________________________________*/
static term domexp2(term a, term b)
/* called for domain(a^b). Assume that if b is a fraction or negated
fraction then b is already in lowest terms. Neglects the possibility
of non-obvious rational exponents as discussed above. */
{ term p,num,den,apos,anonneg;
double z,saveit;
p = domain(a);
if(obviously_positive(a))
return reduced_and(p,domain(b));
/* example: 2^((x^2 + c)/(x^2-c)) */
if(get_currentline() >= 0 || get_binders())
/* This isn't done during the initial domain computations, unless
we're inside a limit or integral where the binder inequalities may help */
{ apos = lpt(lessthan(zero,a));
if(equals(apos,trueterm))
return lpt(reduced_and(p,domain(b)));
anonneg = lpt(le(zero,a));
if(equals(anonneg,trueterm))
{ if(equals(p,trueterm))
return lpt(lessthan(zero,b));
return lpt(reduced_and(p,lessthan(zero,b)));
}
}
if(FUNCTOR(b)=='-')
{ term c = ARG(0,b);
if(INTEGERP(c) || /* a common case */
obviously_positive(c)
)
return lpt(reduced_and(p,lpt(ne(zero,a))));
else if RATIONALP(c) /* integer num and denom */
{ if(ISODD(ARG(1,c)) && !ZERO(ARG(0,c)))
return lpt(reduced_and(p,ne(zero,a)));
else /* to have a^-(../even) defined we must have a > 0 */
return lpt(reduced_and(p,lessthan(zero,a)));
}
return lpt(reduced_and(lpt(ne(zero,a)),domexp(a,ARG(0,b))));
}
/* Now we may assume b isn't a negation */
if(INTEGERP(b) && !ZERO(b)) /* a very common case */
return p; /* and that's that. */
if(obviously_positive(b))
return p;
if(FUNCTOR(b)=='/')
{ num = ARG(0,b);
den = ARG(1,b);
if(ONE(den))
return domexp2(a,num);
if(INTEGERP(num) && INTEGERP(den)) /* positive rational exponent */
{ if(ISODD(den))
return p; /* as in x^(1/3) or x^(3/5) */
/* else denominator is even, as in x^(1/4) */
return lpt(reduced_and(p,lpt(le(zero,a))));
}
if(isinteger(num) && isinteger(den) && isodd(den))
{ /* example: x^(n/3) */
if(obviously_positive(num) && obviously_positive(den))
return p;
if(obviously_negative(num) && obviously_negative(den))
return p;
if(obviously_negative(num) && obviously_positive(den))
return lpt(reduced_and(p,ne(a,zero)));
if(obviously_positive(num) && obviously_negative(den))
return lpt(reduced_and(p,ne(a,zero)));
return lpt(reduced_and(p,
reduced_or(
lpt(lessthan(zero,num)),
lpt(ne(a,zero))
)
));
}
if(isinteger(num) && isinteger(den) && iseven(den))
/* exponent not necessarily positive */
/* a must be >= zero and if b is negative can't be zero;
and in any event b and a can't both be zero. */
{ if((obviously_negative(num) && obviously_positive(den)) ||
(obviously_positive(num) && obviously_negative(den))
)
return lpt(reduced_and(p,lpt(lessthan(zero,a))));
if((obviously_positive(num) && obviously_positive(den)) ||
(obviously_negative(num) && obviously_negative(den))
)
return lpt(reduced_and(p,lpt(le(zero,a))));
return lpt(reduced_and3(p,le(zero,a),reduced_or(lpt(lessthan(zero,num)),lpt(lessthan(zero,a)))));
}
/* Now the exponent is a fraction which we can't see to be rational,
for example x^(pi/2) or x^(x/2). This will just fall through
to the code below. */
}
/* Rather than clutter up the assumptions with disjunctions about
the possibility of rational exponents, we will just assume that
the base is nonnegative. */
/* Let's see if we can settle whether a and b can be simultaneously zero */
if(ISATOM(a) && !deval(a,&saveit) && saveit != BADVAL)
{ SETVALUE(a,0.0);
deval(b,&z);
if(fabs(z) < VERYSMALL || z == BADVAL)
{ term *atomlist;
int natoms = variablesin(b,&atomlist);
if(natoms == 1 && equals(atomlist[0],a))
{ free2(atomlist);
SETVALUE(a,saveit);
return reduced_and(p,lessthan(zero,a));
/* this catches x^x and x^sin(x) for example */
/* also x^(x^x) since that comes in the z == BADVAL case */
}
}
}
if(ISATOM(b) && !deval(b,&saveit) && saveit != BADVAL)
{ SETVALUE(b,0.0);
deval(a,&z);
if(fabs(z) < VERYSMALL || z == BADVAL)
{ term *atomlist;
int natoms = variablesin(a,&atomlist);
if(natoms == 1 && equals(atomlist[0],b))
{ free2(atomlist);
SETVALUE(b,saveit);
return reduced_and(p,lessthan(zero,a));
}
}
}
if(isinteger(b))
{ /* example, x^k in an indexed sum */
term l,r,x;
if(!infer(le(zero,b)))
return p; /* we don't require lessthan(zero,b), so that
sum(x^k,k,0,n) doesn't require x != 0.
In general if there are integer variables in the
exponent, we assume that when the exponent is
zero it means 1. */
if(!binders_interval(&l,&x,&r) && contains(b,FUNCTOR(x)))
/* The exponent contains a bound index variable. It can't be an
integration variable since we've inferred the exponent is an
integer. */
return lpt(reduced_and(p, ne(a,zero)));
return lpt(reduced_and(le(b,zero),ne(a,zero)));
}
if(!equals(apos,trueterm) && get_binders() && contains(a, FUNCTOR(get_eigenvariable())))
{ if(equals(p,trueterm))
return lpt(reduced_and(le(zero,a),lessthan(zero,b)));
return lpt(reduced_and3(p,le(zero,a),lessthan(zero,b)));
}
if(equals(apos,trueterm))
return lpt(p);
if(equals(p,trueterm))
return lpt(reduced_and(le(zero,a), reduced_or(lpt(lessthan(zero,b)),lpt(lessthan(zero,a)))));
return lpt(reduced_and3(p,le(zero,a), reduced_or(lpt(lessthan(zero,b)),lpt(lessthan(zero,a)))));
/* example: x^x would give 0<x and (0<x or 0<x) which will come to 0<x;
but we handled x^x above, saving this trouble. An example that does
get here would be x^(nx), which would give 0<x and (0<nx or 0<x),
which will simplify to 0 < x.
*/
}
/*_________________________________________________________________________*/
static term domexp1(term a, term b)
/* called for domain(a^b). Assume that if b is a fraction or negated
fraction then b is already in lowest terms. This is used in
algebra and precalculus and takes account of the possibility of
rational exponents */
{ term p,num,den,apos,numint,denint,temp,cancelled,mid;
double x;
int err;
p = domain(a);
apos = lpt(lessthan(zero,a));
if(equals(apos,trueterm))
return lpt(reduced_and(p,domain(b)));
/* example: 2^((x^2 + c)/(x^2-c)) */
if(FUNCTOR(b)=='-')
{ term c = ARG(0,b);
if(INTEGERP(c)) /* a common case */
return lpt(reduced_and(p,lpt(ne(zero,a))));
else if RATIONALP(c) /* integer num and denom */
{ if(ISODD(ARG(1,c)) && !ZERO(ARG(0,c)))
return lpt(reduced_and(p,ne(zero,a)));
else /* to have a^-(../even) defined we must have a > 0 */
return lpt(reduced_and(p,lessthan(zero,a)));
}
return lpt(reduced_and(lpt(ne(zero,a)),domexp1(a,ARG(0,b))));
}
/* Now we may assume b isn't a negation */
if(INTEGERP(b) && !ZERO(b)) /* a very common case */
return p; /* and that's that. */
if(FUNCTOR(b)=='/')
{ num = ARG(0,b);
den = ARG(1,b);
if(INTEGERP(num) && INTEGERP(den)) /* positive rational exponent */
{ if(ISODD(den))
return p; /* as in x^(1/3) or x^(3/5) */
/* else denominator is even, as in x^(1/4) */
return lpt(reduced_and(p,lpt(le(zero,a))));
}
if(INTEGERP(den)) /* example: x^(n/3) */
{ if(ISODD(den))
return lpt(reduced_and3(p, lpt(type(num,INTEGER)), reduced_or(lpt(lessthan(zero,num)),lpt(ne(zero,a)))));
else
return lpt(reduced_and3(p,lpt(le(zero,a)),domain(b)));
}
/* The only way to infer that something is even is if 2 will cancel
out of it. Let's handle that directly here for speed. */
polyval(sum(den,minusone),&mid);
err = cancel(mid,two,&cancelled,&temp);
if(!err) /* denominator is odd if temp is an integer */
{ if(isinteger(temp) && isinteger(num))
return lpt(reduced_and(p, reduced_or(lpt(lessthan(zero,b)),lpt(ne(a,zero)))));
return lpt(reduced_and4(p, /* a defined */
lpt(type(temp,INTEGER)), /* b rational */
lpt(type(num,INTEGER)),
reduced_or(lpt(lessthan(zero,b)), /* exponent positive */
lpt(ne(zero,a)) /* or base nonzero */
)
)
);
}
/* maybe the denominator is provably even, e.g. x^(n/2m) */
err = cancel(den,two,&cancelled,&temp);
if(!err)
return lpt(reduced_and4(p, /* a defined */
domain(b),
reduced_or(lpt(lessthan(zero,b)),lpt(lessthan(zero,a))),
lpt(le(zero,a))
)
);
/* Now we're unable to settle whether den is odd or even */
numint = lpt(type(num,INTEGER));
denint = lpt(type(den,INTEGER));
return lpt(reduced_and3( p, /* a defined */
reduced_or(lpt(lessthan(zero,b)),lpt(ne(zero,a))),
reduced_or(
reduced_and3(numint,denint, /* b is rational */
reduced_or(odd(den),lpt(le(zero,a)))
),
lpt(lessthan(zero,a))
)
)
);
}
/* Now FUNCTOR(b) != '/' or '-' */
if(seminumerical(b) && deval(b,&x) && x != BADVAL) /* catch e.g. x^sqrt(5) so we don't return
something involving odd(denom(sqrt 5)) */
{ mid = x > 0.0 ? le(zero,a) : lessthan(zero,a);
return lpt(reduced_and(p,mid));
}
else if(isinteger(b))
{ /* example, x^k in an indexed sum */
term l,r,x;
if(!infer(le(zero,b)))
return p; /* we don't require lessthan(zero,b), so that
sum(x^k,k,0,n) doesn't require x != 0.
In general if there are integer variables in the
exponent, we assume that when the exponent is
zero it means 1. */
if(!binders_interval(&l,&x,&r) && contains(b,FUNCTOR(x)))
/* The exponent contains a bound index variable. It can't be an
integration variable since we've inferred the exponent is an
integer. */
return lpt(reduced_and(p, ne(a,zero)));
return lpt(reduced_and(le(b,zero),ne(a,zero)));
}
mid = lpt(or(odd(denom1(b)),le(zero,a)));
temp = lpt(or(lessthan(zero,b),ne(a,zero)));
/* temp and mid assigned separately to facilitate debugging */
return lpt(reduced_and4(p,domain(b),temp, mid));
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists