Sindbad~EG File Manager
/* M. Beeson, for Mathpert.
Convergence tests for infinite series.
Original date 6.29.98
Last modified 8.28.98
*/
#define SERIES_DLL
#include "globals.h"
#include "prover.h"
#include "limval.h"
#include "intsub.h" /* simple_integral */
#include "pvalaux.h" /* obviously_nonzero */
#include "converge.h"
#include "series2.h" /* eventually_decreasing */
#include "trigpoly.h" /* logexpalg */
/*__________________________________________________________*/
MEXPORT_SERIES int convergence(term t, term *ans)
/* t is an infinite series sum(a[n],n,k,infinity).
Compute *ans, the condition for convergence. In
the case of a seminumerical series, *ans should come out
true or false. In the case of a series in a variable x,
it should come out as a proposition involving x.
Return 0 for success, 1 for failure to compute the
convergence domain. Assumptions may be made along the
way, so *ans is the convergence domain only modulo the
assumptions.
First check for known examples or reductions to known
examples. Then use the root and ratio tests and the
integral test.
*/
{ term n,u,v,r,w,temp,bound;
int err;
term *atomlist;
int nvars;
if(FUNCTOR(t) != SUM)
return 1;
if(!equals(ARG(3,t),infinity))
return 1;
n = ARG(1,t);
u = ARG(0,t);
/* Is this a numerical series or is there a variable? */
nvars = variablesin(u,&atomlist);
if(nvars == 1 && !equals(n,atomlist[0]))
{ if(obviously_nonzero(u))
{ *ans = false;
return 0;
}
*ans = lpt(equation(u,zero)); /* a series with all terms equal to u */
return 0;
}
free2(atomlist);
/* Now nvars == 1 if it's a numerical series */
/* first try the ratio test */
subst(sum(n,one),n,u,&v);
polyval(make_fraction(v,u),&r);
if(!contains(r,FUNCTOR(n)))
{ /* a geometric series */
*ans = lpt(lessthan(abs1(r),one));
return 0;
}
err = limval(limit(arrow(n,infinity),r),&w);
if(!err && !ONE(w))
{ *ans = lpt(lessthan(abs1(w),one));
/* If this condition is satisfied the series is absolutely convergent.
If the series does not have positive terms, there may be
conditional convergence on the boundary of the set thus defined.
Never mind; Mathpert will make this stronger assumption, at least
for now.
*/
return 0;
}
/* Check for alternating signs */
if(!alternating_signs(u,n,ARG(2,t),&temp))
{ err = eventually_decreasing(temp,ARG(2,t),n,&bound);
if(!err)
{ *ans = true;
return 0;
}
}
/* ratio test failed, try the root test */
polyval(make_power(u,reciprocal(n)),&r);
err = limval(limit(arrow(n,infinity),r),&w);
if(!err && !ONE(w))
{ *ans = lpt(lessthan(w,one));
return 0;
}
/* check that the general term tends to zero */
err = limval(limit(arrow(n,infinity),u),&w);
if(err)
return 1; /* if you can't compute the limit of the general term, give up! */
err = check(equation(w,zero));
if(err)
{ *ans = false;
return 0;
}
if(!contains(u,FACTORIAL) &&
( logexpalg(u,n) || /* then it, and its derivatives, have only finitely many zeroes */
!eventually_decreasing(u,n,ARG(2,t),&bound) /* this returns 0 for success, hence the ! */
)
)
{ /* Try the integral test */
err = simple_integral(u,n,&r);
if(!err)
{ err = limval(limit(arrow(n,infinity),r),&w);
if(!err && !ISINFINITE(w))
{ *ans = true;
return 0;
}
if(!err && ISINFINITE(w))
{ *ans = false;
return 0;
}
}
}
return 1;
}
/*___________________________________________________________________________________*/
int alternating_signs(term u, term n, term lo, term *ans)
/* return 0 if u (as a function of n) has alternating signs. If so
return the corresponding positive term (equal to abs(u), but without
absolute value sign) in *ans. Return 1 for non-alternating signs.
It is assumed that n >= lo.
*/
{ unsigned short f = FUNCTOR(u);
unsigned short m = ARITY(u);
term num,denom,newnum,bound;
int i,err;
while(f == '-')
{ u = ARG(0,u);
f = FUNCTOR(u);
}
if(f == '*' && FUNCTOR(ARG(0,u)) == '^' && equals(ARG(0,ARG(0,u)),minusone) &&
(equals(ARG(1,ARG(0,u)),n) ||
(
FUNCTOR(ARG(1,ARG(0,u))) == '+' &&
ARITY(ARG(1,ARG(0,u))) == 2 &&
equals(ARG(0,ARG(1,ARG(0,u))),n) &&
!contains(ARG(1,ARG(1,ARG(0,u))),FUNCTOR(n))
)
)
)
{ if(m==2)
*ans = ARG(1,u);
else
{ *ans = make_term('*',(unsigned short)(m-1));
for(i=1;i<m;i++)
ARGREP(*ans, (unsigned short)(i-1),ARG(i,u));
}
err = infer(le(zero,*ans));
if(!err)
{ err = eventually_decreasing(*ans,n,lo, &bound);
if(!err)
return 0;
}
return 1;
}
if(FRACTION(u))
{ num = ARG(0,u);
denom = ARG(1,u);
if(FUNCTOR(num) == '^' && equals(ARG(0,num),minusone) &&
( equals(ARG(1,num),n) ||
(
FUNCTOR(ARG(1,num)) == '+' && ARITY(ARG(1,num)) == 2 &&
equals(ARG(0,ARG(1,num)),n) && !contains(ARG(1,ARG(1,num)),FUNCTOR(n))
)
)
)
{ *ans = reciprocal(denom);
if(!eventually_decreasing(*ans,n,lo,&bound))
return 0;
return 1;
}
if(FUNCTOR(num) == '*' && FUNCTOR(ARG(0,num)) == '^' && equals(ARG(0,ARG(0,num)),minusone) &&
(equals(ARG(1,ARG(0,num)),n) ||
(
FUNCTOR(ARG(1,ARG(0,num))) == '+' &&
ARITY(ARG(1,ARG(0,num))) == 2 &&
equals(ARG(0,ARG(1,ARG(0,num))),n) &&
!contains(ARG(1,ARG(1,ARG(0,num))),FUNCTOR(n))
)
)
)
{ if(ARITY(num) == 2)
*ans = make_fraction(ARG(1,num),denom);
else
{ m = ARITY(num);
newnum = make_term('*',(unsigned short)(m-1));
for(i=1;i<m;i++)
ARGREP(newnum,(unsigned short)(i-1),ARG(i,num));
*ans = make_fraction(newnum,denom);
}
err = infer(le(zero,*ans));
if(!err)
{ err = eventually_decreasing(*ans,n,lo,&bound);
if(!err)
return 0;
}
}
}
return 1;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists