Sindbad~EG File Manager
/*
M. Beeson. One-step limit calculation
10.2.91 original date
1.29.98 last modified
2.28.00 improved limval_quo to catch e^poly/poly and poly/e^poly without
using l'Hopital's rule (and hence risking a stack overflow if the degree is
over about 10, using the Borland compiler, although it works fine in
Mathpert32.
*/
#include <string.h>
#include <assert.h>
#include "globals.h"
#include "ops.h"
#include "calc.h"
#include "prover.h"
#include "polynoms.h"
#include "order.h"
#include "deriv.h"
#include "mplimits.h"
#include "cancel.h"
#include "pvalaux.h"
#include "limval2.h"
#include "probtype.h"
#include "autocalc.h" /* stop_lhopital */
#include "trigpoly.h" /* algpoly */
#include "autosimp.h" /* SaveShowStepState, RestoreShowStepState */
#define LHOPITAL_MAX 4 /* max number of times to use L'Hopital's rule
on functions without a 'leading term' (such as exponentials or logs);
in other words the maximum depth of nesting of such functions allowed
in indeterminate forms that limval can calculate--except it keeps
going if num or denom is a polynomial. */
static int finish_at_infinity(term a, term d, term *ans, approach *l, approach *r);
static int easy_lhopital(term t,term *ans);
static int limvalquo(term t, term *ans);
static int contains_negpower(term t, term x);
static void logreduce(term t, term x, term *ans);
/*_________________________________________________________________*/
static int lhopital_depth = 0;
/* This static global counts repetitions of L'Hopital's rule to
stop infinite regress by continued differentiation. It is reset
to 0 at each call to limval by the following function.
*/
void set_lhopital_depth(int n)
{ lhopital_depth = n;
}
int get_lhopital_depth(void)
{ return lhopital_depth;
}
/*_________________________________________________________________*/
static int limvalquo(term t, term *ans)
/* t is a limit of a quotient. Get the answer if possible.
Zero return is success. Return value 2 means domain error
(the limit point is not in the closure of the domain of the
limitand).
*/
{ term x,a,u,v,temp,temp1,temp2,c,d,mid,num,den,numlim,denlim;
approach ll,rr,l2,r2;
int err,err2,cflag,dflag;
int dir = 0; /* initialize to avoid a warning message */
unsigned n;
if(FUNCTOR(t) != LIMIT)
return 1;
n = ARITY(t);
assert(FUNCTOR(ARG(0,t))==ARROW);
x = ARG(0,ARG(0,t));
assert(ISATOM(x));
a = ARG(1,ARG(0,t));
if(n==2)
u = ARG(1,t); /* so t = lim(x->a,u) */
else
{ u = ARG(2,t);
dir = equals(ARG(1,t),left) ? LEFTDIR : RIGHTDIR;
}
assert(FUNCTOR(u)=='/');
if(equals(a,minusinfinity))
{ subst(tnegate(x),x,u,&c);
u = c;
a = infinity;
t = limit(arrow(x,a),u); /* one-sided limits at infinity not allowed
so this must be a two-sided limit */
}
num = ARG(0,u);
den = ARG(1,u);
numlim = n==2 ? limit(ARG(0,t),num) : limit3(ARG(0,t),ARG(1,t),num);
denlim = n==2 ? limit(ARG(0,t),den) : limit3(ARG(0,t),ARG(1,t),den);
err = limval_aux(1,denlim,&d,&l2,&r2);
if(err)
return err;
err2 = limval_aux(1,numlim,&c,&ll,&rr);
if(err2)
return err2;
cflag = NOTDEFINED(c);
dflag = NOTDEFINED(d);
if(
(equals(c,undefined) && !dflag) ||
(equals(d,undefined) && !cflag)
)
{ *ans = undefined;
return 0;
}
if(!cflag && !dflag)
/* When written
if(!NOTDEFINED(c) && !NOTDEFINED(d))
this line caused an unexplained crash; in the
debugger control jumped from here to 'nospace'.
As a workaround I introduced cflag and dflag.
*/
{ err = check1(nonzero(d));
if(!err)
{ *ans = make_fraction(c,d);
return 0;
}
/* Now d is zero */
err = check1(nonzero(c));
if(err) /* both d and c are zero */
{ /* Before using lhopital, check for x/abs(x),
because differentiating abs(x) just produces x/abs(x)
again, getting nowhere */
num = ARG(0,u);
den = ARG(1,u);
if( FUNCTOR(num) == ABSFUNCTOR)
{ mid = n==2 ? limit(ARG(0,t),ARG(0,num)):
limit3(ARG(0,t),ARG(1,t),ARG(0,num));
err = limval_aux(0,mid,&d,&l2,&r2);
if(err)
return err;
if((n==2 && l2==r2 && r2==min) ||
(n==3 && dir == RIGHTDIR && r2==min) ||
(n==3 && dir == LEFTDIR && l2 == min)
)
{ c = make_fraction(ARG(0,num),den);
mid = n==2 ? limit(ARG(0,t),c):
limit3(ARG(0,t),ARG(1,t),c);
return limval(mid,ans);
}
if((n==2 && l2==r2 && r2==max) ||
(n==3 && dir == RIGHTDIR && r2==max) ||
(n==3 && dir == LEFTDIR && l2==max)
)
{ c = make_fraction(ARG(0,num),den);
mid = n==2 ? limit(ARG(0,t),c):
limit3(ARG(0,t),ARG(1,t),c);
err = limval(mid,ans);
if(err)
return 1;
*ans = tnegate(*ans);
return 0;
}
else
{ *ans = undefined;
return 0;
}
}
if( FUNCTOR(den) == ABSFUNCTOR)
{ mid = n==2 ? limit(ARG(0,t),ARG(0,den)):
limit3(ARG(0,t),ARG(1,t),ARG(0,den));
err = limval_aux(0,mid,&d,&l2,&r2);
if(err)
return err;
if((n==2 && l2==r2 && r2==min) ||
(n==3 && dir == RIGHTDIR && r2==min) ||
(n==3 && dir == LEFTDIR && l2 == min)
)
{ c = make_fraction(num,ARG(0,den));
mid = n==2 ? limit(ARG(0,t),c):
limit3(ARG(0,t),ARG(1,t),c);
return limval(mid,ans);
}
if((n==2 && l2==r2 && r2==max) ||
(n==3 && dir == RIGHTDIR && r2==max) ||
(n==3 && dir == LEFTDIR && l2==max)
)
{ c = make_fraction(num,ARG(0,den));
mid = n==2 ? limit(ARG(0,t),c):
limit3(ARG(0,t),ARG(1,t),c);
err = limval(mid,ans);
if(err)
return 1;
*ans = tnegate(*ans);
return 0;
}
else
{ *ans = undefined;
return 0;
}
}
return easy_lhopital(t,ans);
}
/* Now the denom goes to zero but the num does not,
so we need the direction of approach of the denom;
we don't have it since the first parameter of limval_aux
above was 1. */
err = limval_aux(0,denlim,&d,&l2,&r2);
if(err == 2)
return 2; /* domain error, function undefined near limit point */
if(err)
{ *ans = undefined; /* really it's plus or minus infinity */
return 0;
}
if(l2==damped_oscillation)
{ *ans = unbounded_oscillations;
return 0;
}
err = infer(lessthan(zero,c));
if(!err)
{ if(n==3 && dir == LEFTDIR)
*ans = l2 == min ? infinity : minusinfinity;
else if(n==3 && dir == RIGHTDIR)
*ans = r2 == min ? infinity : minusinfinity;
else /* n==2 */
*ans = (r2==min && l2==min) ? infinity :
(r2==max && l2==max) ? minusinfinity :
undefined;
return 0;
}
err = infer(lessthan(c,zero));
if(!err)
{ if(n==3 && dir == LEFTDIR)
*ans = l2 == max ? infinity : minusinfinity;
else if(n==3 && dir == RIGHTDIR)
*ans = r2 == max ? infinity : minusinfinity;
else /* n==2 */
*ans = (r2==min && l2==min) ? minusinfinity :
(r2==max && l2==max) ? infinity :
undefined;
return 0;
}
/* can't determine sign of c */
*ans = undefined;
return 0;
}
if(!NOTDEFINED(d)) /* and c is NOTDEFINED */
{ if(ZERO(d))
{ if(WILD(c))
{ *ans = equals(c,bounded_oscillations) ? unbounded_oscillations : c;
return 0;
}
/* e.g. lim(x->0+, (ln x)/ sqrt x) */
if(n==3 && dir==RIGHTDIR)
{ *ans = r2==min ? c : r2==max ? tnegate(c) : undefined;
return 0;
}
if(n==3 && dir==LEFTDIR)
{ *ans = l2==min ? c : l2==max? tnegate(c): undefined;
return 0;
}
if(n==2)
{ *ans = (l2==min && r2==min) ? c : (l2==max && r2==max) ? tnegate(c) : undefined;
return 0;
}
}
err = infer(lessthan(zero,d));
if(!err)
{ *ans = c;
return 0;
}
err = infer(lessthan(d,zero));
if(!err)
{ *ans = equals(numlim,infinity) ? minusinfinity : infinity;
return 0;
}
/* e.g. lim(x->0+, (ln x)/ sqrt x) */
return 1; /* because sign of d is unknown */
}
if(!NOTDEFINED(c)) /* and d is NOTDEFINED */
{ if(equals(d,infinity) || equals(d,minusinfinity))
{ *ans = zero;
return 0;
}
if(equals(d,undefined))
{ *ans = undefined;
return 0;
}
if(ZERO(c))
{ *ans = equals(d,bounded_oscillations) ? unbounded_oscillations : d;
return 0;
}
err = infer(nonzero(c));
if(!err)
*ans = d;
else
*ans = undefined;
return 0;
}
/* Now both c and d are NOTDEFINED */
if(ISINFINITE(c) && ISINFINITE(d))
{ /* catch poly(x)/e^poly(x) */
if(FUNCTOR(den) == '^' &&
(equals(ARG(0,den),eulere) || POSNUMBER(ARG(0,den))) &&
ispolyin(num,x) &&
ispolyin(ARG(1,den),x) &&
equals(a,infinity) /* superfluous theoretically but let's be defensive */
)
{ /* We need to know the leading term of the polynomial in the exponent */
POLYnomial q;
err = makepoly(ARG(1,den),x,&q);
if(!err && obviously_positive(ARG(ARITY(q)-1,q)))
{ *ans = zero;
return 0;
}
if(!err && obviously_negative(ARG(ARITY(q)-1,q)))
{ /* Now we need the leading term of the numerator */
err = makepoly(num,x,&q);
if(!err && obviously_positive(ARG(ARITY(q)-1,q)))
{ *ans = infinity;
return 0;
}
if(!err && obviously_negative(ARG(ARITY(q)-1,q)))
{ *ans = minusinfinity;
return 0;
}
}
}
/* catch e^poly(x)/poly(x) */
if(FUNCTOR(num) == '^' &&
(equals(ARG(0,num),eulere) || POSNUMBER(ARG(0,num))) &&
ispolyin(den,x) &&
ispolyin(ARG(1,num),x) &&
equals(a,infinity) /* superfluous theoretically but let's be defensive */
)
{ /* We need to know the leading term of the polynomial in the exponent */
POLYnomial q;
err = makepoly(ARG(1,num),x,&q);
if(!err && obviously_negative(ARG(ARITY(q)-1,q)))
{ *ans = zero;
return 0;
}
if(!err && obviously_positive(ARG(ARITY(q)-1,q)))
{ /* Now we need the leading term of the denominator */
err = makepoly(den,x,&q);
if(!err && obviously_positive(ARG(ARITY(q)-1,q)))
{ *ans = infinity;
return 0;
}
if(!err && obviously_negative(ARG(ARITY(q)-1,q)))
{ *ans = minusinfinity;
return 0;
}
}
}
err = easy_lhopital(t,ans);
if(!err)
return 0;
/* example: lim(x->infinity, 3^(x-1)/5^x) gets here */
/* Following code handles limits of quotients of exponentials */
if(FUNCTOR(num) == '^' && FUNCTOR(den) == '^' &&
contains(ARG(1,num),FUNCTOR(x)) &&
contains(ARG(1,den),FUNCTOR(x))
)
{ if(equals(ARG(0,num),eulere) && equals(ARG(0,den),eulere))
v = sum(ARG(1,num),tnegate(ARG(1,den)));
else if(equals(ARG(0,num),eulere))
v = sum(
ARG(1,num),
tnegate(product(ln1(ARG(0,den)),ARG(1,den)))
);
else if(equals(ARG(0,den),eulere))
v = sum(
product(ln1(ARG(0,num)),ARG(1,num)),
tnegate(ARG(1,den))
);
else
v = sum(
product(ln1(ARG(0,num)),ARG(1,num)),
tnegate(product(ln1(ARG(0,den)),ARG(1,den)))
);
mid = n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
err = limval(mid,&temp);
if(!err)
{ if(equals(temp,minusinfinity))
{ *ans = zero;
return 0;
}
if(NOTDEFINED(temp))
{ *ans = temp; /* infinity, bounded_oscillations,
unbounded_oscillations */
return 0;
}
polyval(make_power(eulere,temp),ans);
return 0;
}
return 1;
}
if(
(FUNCTOR(num) == '*' || FUNCTOR(den) == '*')
&& !contains(num,LN) && !contains(den,LN) // don't create ln(ln..) terms
)
{ /* example: lim(x->infinity, x 3^(x-1)/ 5^x) gets here */
logreduce(num,x,&temp1);
logreduce(den,x,&temp2);
polyval(sum(temp1,strongnegate(temp2)),&temp);
mid = n==2 ? limit(ARG(0,t),temp) : limit3(ARG(0,t),ARG(1,t),temp);
err = limval(mid,ans);
if(!err)
{ if(equals(*ans,minusinfinity))
{ *ans = zero;
return 0;
}
if(NOTDEFINED(*ans))
{ /* infinity, bounded_oscillations,
unbounded_oscillations */
return 0;
}
polyval(make_power(eulere,*ans),ans);
return 0;
}
}
return 1; /* final failure, limit too complicated */
}
if(equals(c,undefined) || equals(d,undefined))
{ *ans = undefined;
return 0;
}
if(equals(c,bounded_oscillations) && ISINFINITE(d))
{ *ans = zero;
return 0;
}
if(equals(c,unbounded_oscillations) && ISINFINITE(d))
return 1; /* d might kill the oscillations: (x sin x)/e^x for example */
if(equals(d,bounded_oscillations))
return 1; /* e.g. lim(x->\infinity , x/(2+sin x)) = \infinity , but we can't get it */
return 1; /* can't get any more actually */
}
/*_________________________________________________________________*/
static int triglinear(term t, term x)
/* return 1 if t is sin(u), cos(u), or e^u where u is linear in x,
or a sum of such things, or if t doesn't contain x; return 0 otherwise.
*/
{ unsigned short n,f;
int i;
if(NEGATIVE(t))
t = ARG(0,t);
f = FUNCTOR(t);
n = ARITY(t);
if(f == '+')
{ for(i=0;i<n;i++)
{ if(!triglinear(ARG(i,t),x))
return 0;
}
return 1;
}
if(f == SIN || f == COS)
return is_linear_in(ARG(0,t),x);
if(f == '^' && !contains(ARG(0,t),FUNCTOR(x)))
return is_linear_in(ARG(1,t),x);
return contains(t,FUNCTOR(x)) ? 0 : 1;
}
/*_________________________________________________________________*/
static int one_exponential(term t, term x)
/* t is assumed to be a sum.
Return the number of exponential summands with exponent linear
in x; or if this number is more than one, just return 2.
Return -1 if any summand contains a nonlinear exponent.
All other summands must be gpolys; if not return -1.
*/
{ unsigned short n = ARITY(t);
int i,count;
term u,c,s;
if(FUNCTOR(t) != '+')
return 0; /* assert(0) */
count = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(NEGATIVE(u))
u = ARG(0,u);
if(FUNCTOR(u) == '*')
{ twoparts(u,x,&c,&s);
u = s;
}
if(FUNCTOR(u) == '^')
{ if( is_linear_in(ARG(1,u),x) &&
!contains(ARG(0,u),FUNCTOR(x))
)
{ ++count;
if(count > 1)
return 2;
continue;
}
else if(contains(ARG(1,u),FUNCTOR(x)))
return -1;
}
if(!gpoly(u,x))
return -1;
}
return count;
}
/*_________________________________________________________________*/
int lhopital_certain(term num, term den, term x)
/* return 1 if lhopital is certain to work on lim(x->a, num/den),
namely if both are mvpolys, or one is e ^cx or e^-cx or sin or cos of
a linear function of x and the other is an mvpoly.
*/
{ term temp;
int flag1,flag2;
int count1, count2;
flag1 = gpoly(num,x);
flag2 = gpoly(den,x);
/* gpoly is defined in polynoms.c, roughly "polynomial" */
if(flag1 && flag2)
return 1;
if(!flag1 && !flag2)
/* example: (e^x+x^2)/(e^-x + x^2)
bad example: (e^x + e^-x)/(e^2x-e^-2x)
There must be only one exponential in the sum */
{ if(FUNCTOR(num) == '+')
{ count1 = one_exponential(num,x);
if(count1 < 0 || count1 > 1)
return 0;
}
if(FUNCTOR(den) == '+')
{ count2 = one_exponential(den,x);
if(count2 < 0 || count2 > 1)
return 0;
}
if(FUNCTOR(num) == '+' && FUNCTOR(den) == '+')
return 1;
if(FUNCTOR(num) == '+' && FUNCTOR(den) == '^' &&
is_linear_in(ARG(1,den),x)
)
return 1;
if(FUNCTOR(den) == '+' && FUNCTOR(num) == '^' &&
is_linear_in(ARG(1,num),x)
)
return 1;
return 0;
}
if(flag1)
{ temp = den; /* swap num and denom */
den = num;
num = temp;
}
/* now den is a gpoly. Check for e^x or sin x etc in the numerator */
return triglinear(num,x);
}
/*_________________________________________________________________*/
static int easy_lhopital(term t,term *ans)
/* t is a limit of a quotient which is known to have an indeterminate form */
/* get the answer by lhopital's rule in many cases. But don't do it
if either num or denom contains exponentials with non-constant exponents,
or fractional powers or roots (unless the base has a nonzero finite limit or
one of num or denom is an mvpoly);
*/
{ term x,u,v,num,den,a;
unsigned n;
approach l,r;
int ok;
if(FUNCTOR(t) != LIMIT)
return 1;
if(stop_lhopital(t))
return 1;
n = ARITY(t);
assert(FUNCTOR(ARG(0,t))==ARROW);
x = ARG(0,ARG(0,t));
a = ARG(1,ARG(0,t));
assert(ISATOM(x));
u = LIMITAND(t);
assert(FUNCTOR(u)=='/');
num = ARG(0,u);
den = ARG(1,u);
ok = lhopital_certain(num,den,x);
if(!ok && lhopital_depth > LHOPITAL_MAX)
return 1;
if(!ok &&
(
(lhopital_warning(num,x,a) && !mvpoly(den)) ||
(lhopital_warning(den,x,a) && !mvpoly(num)) ||
contains_etonegpower(num,x) ||
contains_etonegpower(den,x)
/* don't use lhopital on e^(1/x)/x for example; it just gets worse */
)
)
return 1; /* give up */
num = derivative(ARG(0,u),x);
den = derivative(ARG(1,u),x);
polyval(make_fraction(num,den),&u);
v = n==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
++lhopital_depth;
return limval_aux(1,v,ans,&l,&r);
/* In effect this is limval(v,ans), but that would also
reset lhopital_depth to zero, rendering it ineffective.
*/
}
/*_________________________________________________________________*/
int limvalquo_aux(int topcall, term t, term *ans, approach *l, approach *r)
/* auxiliary of limval_aux that handles limits of quotients that are
not just rational functions. */
/* inputs and outputs are as for limval_aux */
{ term x,a,u,mid,c,d,num,den,arg;
term a1,a2,u1,u2,d1,d2;
int complex = get_complex();
approach ll,rr,l2,r2;
int saveit, err, err2;
int dir = 0; /* initialize to avoid a warning message */
unsigned n;
if(FUNCTOR(t) != LIMIT)
return 1;
ll = rr = l2 = r2 = unknown; // silence warnings about possibly uninitialized variables
n = ARITY(t);
assert(FUNCTOR(ARG(0,t))==ARROW);
x = ARG(0,ARG(0,t));
assert(ISATOM(x));
a = ARG(1,ARG(0,t));
if(n==2)
u = ARG(1,t); /* so t = lim(x->a,u) */
else
{ u = ARG(2,t);
dir = equals(ARG(1,t),left) ? LEFTDIR : RIGHTDIR;
}
assert(FUNCTOR(u)=='/');
num = ARG(0,u);
den = ARG(1,u);
if(!contains_in_exponent(u,FUNCTOR(x)))
/* example: lim(x->0, ln(1+sqrt x)/sqrt x) */
/* example, (x-16)/( x^(1/4)-2) */
{ char buffer[DIMREASONBUFFER];
int savenvariables = get_nvariables();
int savenextdefn = get_nextdefn();
short savenextassumption = get_nextassumption();
int saveeigen = get_eigenindex();
SETFUNCTOR(arg,ILLEGAL,0);
SaveShowStepState();
err = changelimitvariable(t,arg,&mid,buffer);
RestoreShowStepState(); /* changelimitvariable can call SetShowStepArg */
if(!err)
{ err = limval_aux(topcall,mid,ans,l,r);
if(!err)
{ set_nvariables(savenvariables);
set_nextdefn(savenextdefn);
set_nextassumption(savenextassumption);
set_eigenvariable(saveeigen);
return 0;
}
}
set_nvariables(savenvariables);
set_nextdefn(savenextdefn);
set_nextassumption(savenextassumption);
set_eigenvariable(saveeigen);
}
/* although leading_term would calculate correctly on u, if it fails
we want the results on num and den separately to be available.
Therefore we imitate the code for '/' from leading_term */
err = leading_term(num,x,a,&u1,&d1);
if(err == 2)
return 2; /* domain error */
err2 = leading_term(den,x,a,&u2,&d2);
if(err2 == 2)
return 2; /* domain error */
if(!err && !err2 &&
!equals(u2,bounded_oscillations) &&
!check1(nonzero(u2)) /* leading_term would succeed */
)
{ saveit = get_polyvalfunctionflag();
set_polyvalfunctionflag(1);
if(equals(u1,bounded_oscillations))
c = bounded_oscillations;
else
polyval(make_fraction(u1,u2),&c);
polyval(sum(d1,tnegate(d2)),&d);
set_polyvalfunctionflag(saveit);
return finish_from_leading_term(topcall,u,x,a,c,d,n,dir,ans,l,r);
}
if(topcall) /* style of approach not required */
return limvalquo(t,ans);
/* So from now on topcall == 0 */
if(equals(a,infinity) || equals(a,minusinfinity))
{ if(equals(u,x))
{ *ans = a;
*l = complex ? complex_approach : min;
*r = complex ? complex_approach : max;
return 0;
}
if(!contains_in_exponent(u,FUNCTOR(x))) /* don't create e^(1/x) */
{ approach l1,r1;
term temp;
subst(reciprocal(x),x,u,&mid);
/* limits at infinity reduce to one-sided limits at zero, e.g.
lim(x->inf,x) = lim(x->0+,1/x) = infinity. This will
not work right for complex numbers if we wish to distinguish
between complex_infinity and infinity. But MathXpert only
works with real limits anyway. */
// following paragraph corrected 6.8.13
err = limval_aux(0,limit3(arrow(x,zero),equals(a,infinity) ? right : left,mid),&temp,&l1,&r1);
if(equals(a,infinity))
{ *r = dom_error;
if(ZERO(temp) && r1==min)
{ *ans = infinity;
*l = max;
return 0;
}
else if(ZERO(temp) && r1 ==max)
{ *ans = minusinfinity;
*l = min;
return 0;
}
else if(!infer(nonzero(temp)))
{ *ans = reciprocal(temp);
*l = r1==min ? max : r1==max? min : r1;
return 0;
}
else
return 1;
}
else if(equals(a,minusinfinity))
{ *l = dom_error;
if(ZERO(temp) && r1==min)
{ *ans = infinity;
*r = max;
return 0;
}
else if(ZERO(temp) && r1 ==max)
{ *ans = minusinfinity;
*r = min;
return 0;
}
else if(!infer(nonzero(temp)))
{ *ans = reciprocal(temp);
*r = l1==min ? max : l1==max? min : l1;
return 0;
}
else
return 1;
}
}
}
/* Now a is not infinite, or else u contains the eigenvariable in an exponent. */
c = n==2 ? limit(ARG(0,t),num) : limit3(ARG(0,t),ARG(1,t),num);
d = n==2 ? limit(ARG(0,t),den) : limit3(ARG(0,t),ARG(1,t),den);
if(err) /* numerator had no leading term */
{ err = limval_aux(0,c,&a1,&ll,&rr);
if(err)
return 1;
if(equals(a1,undefined))
{ *ans = undefined;
return 0;
}
}
else /* get a1,ll,rr from the leading term */
{ if(ZERO(d1)) /* finite nonzero limit in num */
{ err = check1(nonzero(u1));
if(err)
return 1; /* l2 and r2 don't matter */
if(complex)
{ a1 = u1;
rr = ll = complex_approach;
}
else
{ err = check1(lessthan(zero,u1));
a1 = err ? tnegate(u1) : u1;
}
}
else
{ err = finish_it(n,dir,d1,&a1,&ll,&rr);
if(err)
return 1;
}
}
if(err2) /* denominator had no leading term */
{ err = limval_aux(0,d,&a2,&l2,&r2);
if(err)
return err;
if(equals(a2,undefined))
{ *ans = undefined;
return 0;
}
}
else /* get a2,l2,r2 from the leading term */
{ if(ZERO(d2)) /* finite nonzero limit in denom */
{ err = check1(nonzero(u2));
if(err)
return 1;
/* l2 and r2 don't matter */
if(complex)
{ *ans = a1;
*r = *l = complex_approach;
return 0;
}
err = check1(lessthan(zero,u2));
if(!err)
{ *ans = a1;
*r = rr;
*l = ll;
return 0;
}
else
{ *ans = equals(a1,infinity) ? minusinfinity : a1;
*r = INVERT_APPROACH(rr);
*l = INVERT_APPROACH(ll);
}
}
err = finish_it(n,dir,d2,&a2,&l2,&r2);
if(err)
return err;
}
/* Now we have the limit = a1/a2, where a2
is zero or infinity, but a1 might still be finite.
Can we calculate it? */
if((ISINFINITE(a1) && ISINFINITE(a2))
|| (ZERO(a1) && ZERO(a2))
) /* then use L'Hopital unless we've already done so too
many times; but use it anyway if the numerator or denominator
is a polynomial. */
{ if(lhopital_depth == LHOPITAL_MAX && !mvpoly(den) && !mvpoly(num))
return 1;
++lhopital_depth;
c = make_fraction(derivative(num,x), derivative(den,x));
mid = n==2 ? limit(ARG(0,t),c) : limit3(ARG(0,t),ARG(1,t),c);
err = limval_aux(0,mid,ans,l,r);
/* if there were logarithms, after differentiating the
new limit can be defined on the left or right where
the old one was not. Fix this up now. */
if(ll==dom_error || l2 == dom_error)
*l = dom_error;
if(rr==dom_error || r2 == dom_error)
*r = dom_error;
return err;
}
if(complex)
{ if( !WILD(a1) && ISINFINITE(a2))
{ *ans = zero;
*l = *r = complex_approach;
return 0;
}
if(ZERO(a2) && !WILD(a1))
{ *ans = infinity;
*l = *r = complex_approach;
return 0;
}
return 1;
}
return limquo_aux(n,dir,a1,ll,rr,a2,l2,r2,ans,l,r);
}
/*________________________________________________________________*/
int finish_from_leading_term(int topcall,term u,term h, term a,term c,term d,
unsigned n,int dir,term *ans,
approach *l,approach *r)
/* calculate lim(h->a, u) from the leading term ch^d, returning
the answer in *ans, and if(!topcall), returning also the approach styles
*l and *r. Return 0 for success, 1 for failure.
n is the arity of the original limit term (2 or 3). If it is 3,
dir is RIGHTDIR or LEFTDIR, and only the relevant one of *l and *r has
to be instantiated.
*/
{ approach ll,rr;
term dd,cc,mid;
int err,sign;
int complex = get_complex();
if(ZERO(d))
{ *ans = c; /* well and good, but what are *l and *r ? */
if(topcall)
return 0; /* without instantiating *l and *r */
if(equals(c,bounded_oscillations))
return 1; /* too complicated */
polyval(sum(u,tnegate(c)),&mid);
err = leading_term(mid,h,a,&cc,&dd);
if(err || ZERO(dd))
return err;
if(obviously_positive(cc))
err = 0;
else if(obviously_nonnegative(strongnegate(cc)))
err = 1;
else
err = check1(lessthan(zero,cc));
if(!err)
return finish_it(n,dir,dd,&mid,l,r); /* mid is irrelevant */
err = finish_it(n,dir,dd,&mid,&ll,&rr);
if(err)
return err;
*l = ll==min ? max : ll == max ? min : ll;
*r = rr==min ? max : rr == max ? min : rr;
return 0;
}
/* Now we can assume d is nonzero. */
if(ISINFINITE(a))
{ err = finish_at_infinity(a,d,ans,l,r);
if(err)
return 1;
if(equals(c,bounded_oscillations))
{ if(ISINFINITE(*ans))
*l = *r = unbounded_oscillation;
else
*l = *r = bounded_oscillation;
return 0;
}
if(!ZERO(*ans) || !topcall)
sign = get_sign(c);
else
sign = 1;
if(sign < 0)
{ *l = REVERSE(*l);
*r = REVERSE(*r);
*ans = tnegate(*ans);
}
return 0;
}
/* Now a is finite */
err = finish_it(n,dir,d,&cc,&ll,&rr);
if(err)
return err;
if(equals(cc,undefined))
{ *ans = undefined;
return topcall ? 0 : 1;
}
if(ZERO(cc) && topcall)
{ *ans = zero;
return 0;
}
if(equals(c,bounded_oscillations))
{ if(ISINFINITE(*ans))
*l = *r = unbounded_oscillation;
else
*l = *r = bounded_oscillation;
return 0;
}
if(complex)
sign = 0;
else if(GRAPHTYPE(get_problemtype()))
{ err = get_sign2(c,&sign);
if(err)
return 1;
}
else
sign = get_sign(c);
if(sign < 0)
{ tneg(cc,ans);
*l = ll==min ? max : ll == max ? min : ll;
*r = rr==min ? max : rr == max ? min : rr;
}
else if(complex)
{ *ans = cc;
*l = *r = complex_approach;
}
else if(sign > 0)
{ *ans = cc;
*l = ll;
*r = rr;
}
else
/* c was zero; leading_term returned a zero leading term */
{ *ans = zero;
return topcall ? 0 : 1;
}
return 0;
}
/*______________________________________________________________*/
static int finish_at_infinity(term a, term d, term *ans, approach *l, approach *r)
/* a is presumed to be infinity or minusinfinity. Calculate
lim(h->infinity, h^d) and return the answer and styles of left and
right approach in *ans, *l, *r respectively. For negative exponents
of unknown parity you can get *r = unknown. This is still considered success
since we got the answer to the limit.
Return 0 for success, 1 for failure. */
{ int err;
int complex = get_complex();
if(equals(a,infinity))
{ err = infer(lessthan(zero,d));
if(!err)
{ *ans = infinity;
*l = complex? complex_approach : max;
*r = complex? complex_approach : dom_error;
return 0;
}
err = infer(lessthan(d,zero));
if(!err)
{ *ans = zero;
*l = complex? complex_approach : min;
*r = complex? complex_approach : dom_error;
return 0;
}
return 1; /* can't determine sign of d */
}
if(equals(a,minusinfinity))
{ err = infer(lessthan(zero,d));
if(!err)
{ if(iseven(d) ||
( FRACTION(d) && isodd(ARG(1,d)) && iseven(ARG(0,d)))
)
{ *ans = infinity;
*r = complex? complex_approach : max;
*l = complex? complex_approach : dom_error;
return 0;
}
if(isodd(d) ||
( FRACTION(d) && isodd(ARG(1,d)) && isodd(ARG(0,d)))
)
{ *ans = minusinfinity;
*r = complex? complex_approach : min;
*l = complex? complex_approach : dom_error;
return 0;
}
return 1;
}
err = infer(lessthan(d,zero));
if(!err) /* negative exponent */
{ *ans = zero;
if(complex)
{ *l = *r = complex_approach;
return 0;
}
*l = dom_error;
if(iseven(d) ||
(NEGATIVE(d) && FRACTION(ARG(0,d)) && iseven(ARG(0,ARG(0,d))) && isodd(ARG(1,ARG(0,d))))
)
{ *r = min;
return 0;
}
if(isodd(d) ||
(NEGATIVE(d) && FRACTION(ARG(0,d)) && isodd(ARG(1,ARG(0,d))) && isodd(ARG(0,ARG(0,d))))
)
{ *r = max;
return 0;
}
*r = unknown;
return 0;
}
}
return 1;
}
/*_____________________________________________________________________*/
int finish_it(int n, int dir, term d,term *ans, approach *l, approach *r)
/* Outputs *ans, *l, *r are as for limval_aux; specifically we are to
Calculate the limit (*ans) of u^d as u->0, and return 0 for success,
and indirectly return in *l and *r the style of approach to the limit.
n is the arity of the
original limit term; if n==3 then dir is LEFTDIR or RIGHTDIR; d is the
exponent of the leading term, which is not zero, so the limit is
zero or infinity or minusinfinity. This function assumes the coefficient
of the leading term is positive (or if complex, only nonzero). */
{ int err;
term num,den,dd,u,v;
int complex = get_complex();
if(ZERO(d))
assert(0);
if(POSNUMBER(d) ||
(! (NEGATIVE(d) && POSNUMBER(ARG(0,d))) &&
/* don't waste time trying to infer 0 < -1/2 */
!infer(lessthan(zero,d))
)
)
{ if(isinteger(d))
{ *ans = zero;
if(iseven(d))
{ *l = *r = min;
return 0;
}
if(isodd(d))
{ *l = max;
*r = min;
return 0;
}
*ans = zero;
*r = min;
*l = unknown;
return 0;
}
if(FUNCTOR(d)=='/')
{ num = ARG(0,d);
den = ARG(1,d);
if(!ONE(num))
{ err = cancel(num,den,&u,&v);
if(!err) /* exponent wasn't in lowest terms */
return finish_it(n,dir,v,ans,l,r);
}
if(isodd(den))
{ if(iseven(num)) /* even/odd, same sign both sides */
{ *ans = zero;
*l = *r = min;
return 0;
}
if(isodd(num)) /* odd num and denom, crosses zero */
{ *ans = zero;
*r = min;
*l = max;
return 0;
}
*ans = zero;
*r = min;
*l = unknown; /* can't determine if num is even or odd */
return 0;
}
if(iseven(den))
{ *ans = zero;
*r = min;
*l = dom_error;
return 0;
}
else
{ /* can't determine sign of denominator */
*ans = zero;
*r = *l = unknown;
return 0;
}
}
/* x^\pi for example would arrive here */
/* positive non-rational, non-integer exponent
or positive rational exponent with non-odd denominator (even or
can't determine) */
if(n==3 && dir == LEFTDIR)
{ *ans = undefined;
*r = min;
*l = dom_error;
return 0;
}
else if (complex)
{ *ans = zero;
*r = *l = complex_approach;
return 0;
}
else
{ *ans = zero;
*r = min;
*l = dom_error;
return 0;
}
}
if(NEGATIVE(d) && POSNUMBER(ARG(0,d)))
err = 0; /* don't bother calling infer to see -1/2 < 0 */
else
err = infer(lessthan(d,zero));
if(!err && complex)
{ *ans = infinity;
*r = *l = complex_approach;
return 0;
}
if(!err) /* && !complex */
{ dd = tnegate(d); /* so dd > 0 */
err = !isinteger(dd);
if(err && FUNCTOR(dd) != '/')
return 1;
if(err) /* rational dd */
{ num = ARG(0,dd);
den = ARG(1,dd);
/* dd comes out in lowest terms from leading_term */
if(iseven(den))
{ if(n==2 || dir == LEFTDIR) /* two sided limit or one-sided from left */
{ *ans = undefined;
*l = dom_error;
return 0;
}
*ans = infinity; /* one-sided from right */
*l = dom_error;
*r = max;
return 0;
}
if(isodd(num)) /* odd num and odd den, alternating signs */
{ if(n==2 && !complex)
{ *ans = undefined;
*r = min;
*l = max;
return 0;
}
if(n==2 && complex)
{ *ans = infinity;
*r = *l = complex_approach;
}
if(dir==RIGHTDIR)
{ *ans = infinity;
*r = max;
}
else /* dir == LEFTDIR */
{ *ans = minusinfinity;
*l = min;
}
return 0;
}
if(iseven(num))
return 1;
/* even num and odd den. Same sign on both sides. */
*ans = infinity;
*l = *r = max;
return 0;
}
/* Now dd is an integer */
if(iseven(dd))
{ /* even exponent, same sign on both sides */
*ans = infinity;
*l = *r = max;
return 0;
}
if(isodd(dd))
{ /* odd integer exponent */
if(n==2 && !complex) /* two-sided limit */
{ *ans = undefined;
*r = max;
*l = min;
return 0;
}
if(n==2 && complex)
{ *ans = infinity;
*l = *r = complex_approach;
return 0;
}
*ans = dir==RIGHTDIR ? infinity : minusinfinity;
*r = max;
*l = min;
return 0;
}
}
return 1;
}
/*________________________________________________________________*/
int limquo_aux(int n, int dir, term a1,approach l1,approach r1, term a2, approach l2, approach r2, term *ans, approach *l, approach *r)
/* a1 and a2 are two limits, approached in the manner described by l1,r1
and l2,r2 respectively; a2 is infinite or zero; a1 can be infinite, zero,
or finite, but not undefined.
Compute the limit and manner of approach of the quotient a1/a2.
It's assumed that we are not working with complex limits.
The integer n is 2 or 3, the arity of the original limit term.
If n==3 then dir is LEFTDIR or RIGHTDIR. Zero return is success. */
{ int err;
if(ZERO(a1) && equals(a2,infinity))
{ *ans = zero;
*r = r2==max ? r1 : r2;
*l = l2==max ? l1 : l2;
return 0;
}
if(ZERO(a1) && equals(a2,minusinfinity))
{ *ans = zero;
*r = r2==min ? (r1 == max ? min : r1==min ? max : r1) : r2;
*l = l2==min ? (l1 == max ? min : l1 == min ? max : l1) : l2;
return 0;
}
if(ZERO(a2) && equals(a1,infinity))
{ if(n==2 && r2==min && l2==min)
{ *ans = infinity;
*l = *r = max;
return 0;
}
if(n==2 && r2==max && l2==max)
{ *ans = minusinfinity;
*l = *r = min;
return 0;
}
if(n==2 && r2 != l2)
{ *ans = undefined;
*l = INVERT_APPROACH(l1);
*r = INVERT_APPROACH(r1);
return 0;
}
if(n==3 && dir == LEFTDIR)
{ if(l2==min)
{ *ans = infinity;
*l = max;
*r = INVERT_APPROACH(r1);
return 0;
}
if(l2==max)
{ *ans = minusinfinity;
*l = min;
*r = INVERT_APPROACH(r1);
return 0;
}
}
if(n==3 && dir==RIGHTDIR)
{ if(r2==min)
{ *ans = infinity;
*r = max;
*l = INVERT_APPROACH(l1);
return 0;
}
if(r2==max)
{ *ans = minusinfinity;
*r = min;
*l = INVERT_APPROACH(l1);
return 0;
}
}
return 1;
}
if(ZERO(a2) && equals(a1,minusinfinity))
return limquo_aux(n,dir,infinity,INVERT_APPROACH(l1),INVERT_APPROACH(r1),zero,INVERT_APPROACH(l2),INVERT_APPROACH(r2),ans,l,r);
/* Now a1 is finite nonzero */
err = check1(lessthan(zero,a1));
if(ZERO(a2))
{ *ans = err ? minusinfinity : infinity;
*l = err ? l2 : INVERT_APPROACH(l2);
*r = err ? r2 : INVERT_APPROACH(r2);
return 0;
}
if(equals(a2,infinity))
{ *ans = zero;
*r = err ? r2 : INVERT_APPROACH(r2);
*l = err ? l2 : INVERT_APPROACH(l2);
return 0;
}
if(equals(a2,minusinfinity))
{ *ans = zero;
*r = !err ? r2 : INVERT_APPROACH(r2);
*l = !err ? l2 : INVERT_APPROACH(l2);
return 0;
}
return 1;
}
/*______________________________________________________________*/
int get_sign(term c)
/* Determine the sign of c; make new assumptions
if necessary until it is determined. Return 1
for positive, -1 for negative, 0 when c is zero. */
{ int err;
if(ZERO(c))
return 0;
if(OBJECT(c) || RATIONALP(c))
return 1;
if(NEGATIVE(c))
return -get_sign(ARG(0,c));
err = check1(lessthan(zero,c));
if(!err)
return 1;
err = check1(lessthan(c,zero));
if(!err)
return -1;
return 0; /* c is provably zero */
}
/*______________________________________________________________*/
int get_sign2(term c, int *sign)
/* Determine the sign of c if possible without making
new assumptions. Set *sign to 1 for positive, -1 for negative,
0 when c is zero, and return 0 for success, 1 for failure.
*/
{ int err;
if(ZERO(c))
{ *sign = 0;
return 0;
}
if(OBJECT(c) || RATIONALP(c))
{ *sign = 1;
return 0;
}
if(NEGATIVE(c))
{ err = get_sign2(ARG(0,c),sign);
if(err)
return 1;
*sign = -*sign;
return 0;
}
if(!infer(lessthan(zero,c)))
{ *sign = 1;
return 0;
}
if(!infer(lessthan(c,zero)))
{ *sign = -1;
return 0;
}
if(!infer(equation(c,zero)))
{ *sign = 0;
return 0;
}
return 1;
}
/*___________________________________________________________________________*/
static int contains_pospower(term t, term x)
/* Return 1 if t contains a positive power of x, not hidden
inside any functor other than -, *, and /. */
{ term c,u,s;
if(NEGATIVE(t))
t = ARG(0,t);
if(equals(t,x))
return 1;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '*')
{ twoparts(t,x,&c,&s);
return contains_pospower(s,x);
}
if(FUNCTOR(t) == '^' && equals(ARG(0,t),x))
{ u = ARG(1,t);
if(obviously_positive(u))
return 1;
return 0;
}
if(FRACTION(t) && contains_pospower(ARG(0,t),x))
return 1;
if(FRACTION(t) && contains_negpower(ARG(1,t),x))
return 1;
return 0;
}
/*___________________________________________________________________________*/
static int contains_negpower(term t, term x)
/* Return 1 if t contains a negative power of x or a (positive or negative)
power of ln x or log x or ln or log of anything containing x, not
hidden inside any functor other than -, *, / .
*/
{ term c,u,s;
if(NEGATIVE(t))
t = ARG(0,t);
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '*')
{ twoparts(t,x,&c,&s);
return contains_negpower(s,x);
}
if(FUNCTOR(t) == '^' &&
(FUNCTOR(ARG(0,t)) == LN || FUNCTOR(ARG(0,t)) == LOG) &&
contains(ARG(0,t),FUNCTOR(x))
)
return 1;
if(FUNCTOR(t) == '^' && equals(ARG(0,t),x))
{ u = ARG(1,t);
if(NEGATIVE(u) && obviously_positive(ARG(0,u)))
return 1;
return 0;
}
if(FRACTION(t) && contains_negpower(ARG(0,t),x))
return 1;
if(FRACTION(t) && contains_pospower(ARG(1,t),x))
return 1;
return 0;
}
/*___________________________________________________________________________*/
int contains_etonegpower(term t, term x)
/* return 1 if t contains e^(1/x) or e^(1/x^2) or e^-1/x, e^(x^-n) etc.,
including e^(powers of ln x)
Return 0 otherwise. Does not deal with nested powers.
*/
{ unsigned short n;
int i;
term u;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^')
{ u = ARG(1,t);
if(!contains(t,FUNCTOR(x)))
return 0;
if(!equals(ARG(0,t),eulere))
return 0;
return contains_negpower(u,x);
}
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_etonegpower(ARG(i,t),x))
return 1;
}
return 0;
}
/*___________________________________________________________________*/
int contains_in_exponent(term t, unsigned short f)
/* return 1 if t contains functor or atom f in an exponent,
0 if not */
{ unsigned short n;
int i;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^')
{ if(contains(ARG(1,t),f))
return 1;
return contains_in_exponent(ARG(0,t),f);
}
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_in_exponent(ARG(i,t),f))
return 1;
}
return 0;
}
/*__________________________________________________________________*/
static void logreduce(term t, term x, term *ans)
/* *ans is formed from ln(t), where t is a power or product, using
ln(ab) = ln a + ln b and ln(a^n) = n ln a, but disregarding terms
a which are algpolys, providing at least one true term with an
algpoly (in x) in the exponent is present. x is the limit variable.
*/
{ unsigned short i,n,f,k;
term u,temp;
int flag = 0;
f = FUNCTOR(t);
if(f == '^' && equals(ARG(0,t),eulere))
{ *ans = ARG(1,t);
return;
}
if(f == '^')
{ *ans = product(ln1(ARG(0,t)),ARG(1,t));
return;
}
if(f != '*')
{ *ans = ln1(t);
return;
}
n = ARITY(t);
for(i=0;i<ARITY(t);i++)
{ u = ARG(i,t);
if(FUNCTOR(u) == '^' && contains(ARG(1,u),FUNCTOR(x)) &&
(!contains(ARG(0,u),FUNCTOR(x)) || algpoly(ARG(0,u)))
)
break;
}
if(i < n)
flag = 1; /* disregard algpoly factors */
temp = make_term('+',n);
k = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(flag && algpoly(u))
continue;
logreduce(u,x,ARGPTR(temp)+k);
++k;
}
if(k==0)
assert(0);
if(k==1)
{ *ans = ARG(0,temp);
RELEASE(temp);
return;
}
*ans = temp;
SETFUNCTOR(*ans,'+',k);
return;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists