Sindbad~EG File Manager
/* M. Beeson, for Mathpert.
Operations for infinite series.
Original date 7.3.98
modified 6.20.99
modified 2.26.00
3.1.00 added series_check and corrected finishlimitcomparisontest
3.2.00 modified comparisontest1 and comparisontest2 and
finishcomparisontest1 and finishcomparistontest2.
4.2.00 modified finishratiotest
7.24.00 changed some reason strings to facilitate German translation
*/
#include <string.h>
#include <assert.h>
#include <math.h>
#define SERIES_DLL
#include "globals.h"
#include "trig.h"
#include "series.h"
#include "sselect.h"
#include "errbuf.h"
#include "limval.h"
#include "deval.h"
#include "pathtail.h" /* set_pathtail */
#include "autosimp.h" /* SetShowStepOperation */
#include "islinear.h"
#include "prover.h" /* NOTDEFINED */
#include "calc.h" /* polyvalop */
#include "converge.h"
#include "trigpoly.h" /* algebraic_in2 */
#include "deriv.h" /* derivative */
#include "cflags.h" /* pushpending, poppending */
#include "graphstr.h" /* document.h needs it */
#include "document.h" /* controldata */
#include "operator.h" /* series4 */
#include "autosimp.h" /* contains_calc */
#include "pvalaux.h" /* obviously_nonnegative */
#include "series2.h"
#include "binders.h"
#include "loglead.h" /* log_leading_term */
#include "polynoms.h" /* POLYnomial etc. */
#include "scontrol.h" /* used4 */
#include "probtype.h"
static term lower_comparison(term u, term n, term lo);
static term upper_comparison(term u, term n, term lo);
static void remove_dependent_assumptions(term n);
/*___________________________________________________________________*/
static int series_check(term t, term n)
/* first, make n the eigenvariable (it must be a variable).
Then set the problemtype to INEQUALITIES, so that check will
not make assumptions involving n. Then call check, and finally
restore the original eigenvariable and problemtype. Return
0 for success (check returned 0) and 1 otherwise.
*/
{ int err,problemtype,eigenindex,nvars,i;
term *varlist;
if(!ISATOM(n))
return 1;
problemtype = get_problemtype();
eigenindex = get_eigenindex();
varlist = get_varlist();
nvars = get_nvariables();
for(i=0;i<nvars;i++)
{ if(equals(n,varlist[i]))
{ set_eigenvariable(i);
break;
}
}
set_problemtype(INEQUALITIES);
err = check(t);
set_eigenvariable(eigenindex);
set_problemtype(problemtype);
return err;
}
/*___________________________________________________________________*/
MEXPORT_SERIES int telescopingseries(term t, term arg, term *next, char *reason)
/* collapse a telescoping series */
{ int err,flag=0,i;
term u,kk,lo,a,b,temp,p,q,w,aval,bval;
unsigned short path[5];
if(FUNCTOR(t) != SUM)
return 1;
if(!equals(ARG(3,t),infinity))
return 1;
kk = ARG(1,t); /* the index variable */
u = ARG(0,t);
if(FUNCTOR(u) != '+' || ARITY(u) != 2)
return 1;
lo = ARG(2,t);
for(i=0;i<2;i++)
{ copy(ARG(i,u),&a);
copy(ARG(i ? 0 : 1,u),&b);
subst(sum(kk,one),kk,a,&temp); /* this puts temp in fresh space; b is in fresh space by copy */
if(NEGATIVE(b) && equals(temp,ARG(0,b)))
{ q = zero; /* in this case, avoid calling polyval */
flag = 1;
}
else
{ p = sum(temp,b); /* therefore p is in fresh space and no damage will be done by clear_already */
clear_already(&p); /* otherwise e.g. b may contain sqrts, and a gets simplified to an equal expression
involving a fractional exponent */
polyval1(p,&q);
}
if(ZERO(q))
break;
destroy_term(a);
destroy_term(b);
}
if(i==2)
return 1; /* failure, neither order of a and b works to make a[k+1] + b[k] == 0 */
/* Now b[k] + a[k+1] == 0 */
err = limval(limit(arrow(kk,infinity),u),&w);
if(err)
{ errbuf(0, english(2238));
/* Mathpert cannot compute the limit of the general term. */
return 1;
}
if(NOTDEFINED(w))
{ errbuf(0, english(2236));
/* the general term does not have a finite limit. */
return 1;
}
if(!flag)
{ /* it's too big a step in some cases if we just jump to the answer. So
first show the simplification of the two terms. */
clear_already(&a);
polyvalop(a,zero,&aval,reason);
clear_already(&b);
polyvalop(b,zero,&bval,reason);
if(!equals(a,aval))
{ path[0] = SUM;
path[1] = 1;
path[2] = '+';
path[3] = 1;
path[4] = 0;
set_pathtail(path);
SetShowStepOperation(polyvalop);
*next = sigma(sum(aval,b),ARG(1,t),ARG(2,t),ARG(3,t));
return 0;
}
else if(!equals(b,bval))
{ path[0] = SUM;
path[1] = 1;
path[2] = '+';
path[3] = 2;
path[4] = 0;
set_pathtail(path);
SetShowStepOperation(polyvalop);
*next = sigma(sum(a,bval),ARG(1,t),ARG(2,t),ARG(3,t));
return 0;
}
}
if(!ZERO(w))
{ subst(lo,kk,a,&temp);
*next = sum(temp, flag ? w : tnegate(w));
}
else
subst(lo,kk,a,next);
HIGHLIGHT(*next);
strcpy(reason,english(2237)); /* telescoping series */
return 0;
}
/*________________________________________________________________________*/
MEXPORT_SERIES int seriessum(term t, term arg, term *next, char *reason)
/* � (u�v) = �u + �v */
{ int i;
unsigned short n;
term u,v,w,dom;
int err;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(!equals(ARG(3,t),infinity) && !equals(ARG(2,t),minusinfinity))
return 1; /* this is only for infinite series */
n = ARITY(u);
*next = make_term('+',n);
for(i=0;i<n;i++)
{ w = ARG(i,u);
if(NEGATIVE(w))
v = sigma(ARG(0,w),ARG(1,t),ARG(2,t),ARG(3,t));
else
v = sigma(w,ARG(1,t),ARG(2,t),ARG(3,t));
err = convergence(v,&dom); /* check convergence */
if(err)
{ errbuf(0, english(2253));
/* Mathpert cannot check the convergence of the series that would result. */
return 1;
}
err = series_check(dom,ARG(1,t));
if(err)
{ errbuf(0, english(2254));
/* The resulting series would be divergent, so the law cannot be applied. */
return 1;
}
ARGREP(*next,i,NEGATIVE(w) ? tnegate(v) : v);
}
if(n==2 && FUNCTOR(ARG(1,u))== '-')
strcpy(reason,"$� (u-v) = �u - �v$");
else
strcpy(reason,"$� (u+v) = �u + �v$");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int eventually_decreasing(term u, term n, term lo, term *bound)
/* return 0 if u is eventually decreasing as n-> infinity,
1 if not, and 2 if we can't determine. In case of zero return,
put in *bound a point past which it is known that u is decreasing.
It is assumed that n >= lo.
*/
{ term du,q,p,s,savelocus;
int i,err,savej;
unsigned short m;
unsigned short f;
varinf *varinfo = get_varinfo();
int savebinderflag = get_lpt_binderflag();
set_lpt_binderflag(0);
/* Now we want to set the binders as they would be on an integral
from lo to infinity */
s = definite_integral(u,n,lo,infinity);
setlocus(n,&savelocus,&savej,s);
fillbinders(s);
du = derivative(u,n);
q = lpt(le(du,zero));
varinfo[savej].locus = savelocus;
releasebinders();
f = FUNCTOR(q);
set_lpt_binderflag(savebinderflag);
if(equals(q,false))
return 1;
if(equals(q,true))
{ *bound = lo;
return 0;
}
if(!contains(q,FUNCTOR(n)))
{ /* example, if u = 1/x^s, then q is 0 < s */
err = series_check(q,n);
*bound = lo;
return err ? 1 : 0;
}
if((f== LE || f == '<') && !contains(ARG(0,q),FUNCTOR(n)) && equals(ARG(1,q),n))
{ *bound = ARG(0,q);
return 0;
}
if((f == '>' || f == GE) && !contains(ARG(1,q),FUNCTOR(n)) && equals(ARG(0,q),n))
{ *bound = ARG(1,q);
return 0;
}
if(f== OR)
{ m = ARITY(q);
for(i=0;i<m;i++)
{ p = ARG(i,q);
if((FUNCTOR(p) == LE || FUNCTOR(p) == '<') && !contains(ARG(0,p),FUNCTOR(n)) && equals(ARG(1,p),n))
{ * bound = ARG(0,p);
return 0;
}
if((FUNCTOR(p) == '>' || FUNCTOR(p) == GE) && !contains(ARG(1,p),FUNCTOR(n)) && equals(ARG(0,p),n))
{ *bound = ARG(1,p);
return 0;
}
}
}
if(interval_as_and(q))
return 1;
if((f == LE || f == '<') && !contains(ARG(1,q),FUNCTOR(n)) && equals(ARG(0,q),n))
return 1;
if((f == '>' || f== GE) && !contains(ARG(0,q),FUNCTOR(n)) && equals(ARG(1,q),n))
return 1;
return 2;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int integraltest(term t, term arg, term *next, char *reason)
/* set up the integral to evaluate for the integral test */
{ term u,n,x,v,w,lo,hi,bound;
int err;
int currentline;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity) && !equals(ARG(2,t),minusinfinity))
return 1; /* this is only for infinite series */
n = ARG(1,t); /* summation variable */
lo = ARG(2,t);
hi = ARG(3,t);
/* u must be a decreasing (or at least non-increasing) function */
/* Or, of course, if it's an increasing function that also works. */
/* if it is algebraic, e.g. logexpalg(u,n), no need to work harder to show it's decreasing,
as algebraic functions have algebraic derivatives, and all functions in this class have
finitely many zeros; but since we want to return *bound, we need to do the work anyway. */
err = limval(limit(arrow(n,infinity),u),&w);
if(err)
{ errbuf(0, english(2238));
/* Mathpert cannot compute the limit of the general term. */
return 1;
}
if(!ZERO(w))
{ errbuf(0, english(2299));
/* The limit of the general term is not zero. */
return 1;
}
err = eventually_decreasing(u,n,lo,&bound);
if(err == 1)
{ if(logexpalg(u,n))
{ bound = infinity; /* means, unknown */
x = getnewvar(t,"xuyzv");
subst(x,n,u,&v);
*next = definite_integral(v,x,lo,hi);
goto out;
}
errbuf(0, english(2260));
/* The general term is not decreasing */
return 1;
}
if(err > 1)
{ errbuf(0, english(2261));
/* Mathpert cannot verify that the general term is decreasing. */
return 1;
}
x = getnewvar(t,"xuyzv");
subst(x,n,u,&v);
if(equals(bound,minusinfinity))
bound = lo;
*next = definite_integral(v,x,bound,hi);
out:
SETIMPROPER(*next);
strcpy(reason, english(2256)); /* evaluate to apply the integral test */
currentline = get_currentline();
pushpending(t,currentline); /* push the integral, not the whole current line */
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int ratiotest(term t, term arg, term *next, char *reason)
/* set up the limit to evaluate for the ratio test */
{ term u,n,v,w;
int err,currentline;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
/* series that start from -infinity need to be changed to this kind first */
n = ARG(1,t); /* summation variable */
subst(sum(n,one),n,u,&v);
err = value(v,&w);
if(err == 0 || err == 2)
v =w;
*next = limit(arrow(n,infinity),make_fraction(v,u));
strcpy(reason, english(2258)); /* evaluate to apply the ratio test */
currentline = get_currentline();
pushpending(t,currentline); /* push the series, not the whole current line */
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int roottest(term t, term arg, term *next, char *reason)
/* set up the limit to evaluate for the ratio test */
{ term u,n;
int currentline;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
/* series that start from -infinity need to be changed to this kind first */
n = ARG(1,t); /* summation variable */
*next = limit(arrow(n,infinity),make_power(u,reciprocal(n)));
strcpy(reason, english(2257)); /* evaluate to apply the root test */
currentline = get_currentline();
pushpending(t,currentline); /* push the integral, not the whole current line */
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int divergencetest(term t, term arg, term *next, char *reason)
/* set up the limit to evaluate for the divergence test */
{ term u,n;
int currentline;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
/* series that start from -infinity need to be changed to this kind first */
n = ARG(1,t); /* summation variable */
*next = limit(arrow(n,infinity),u);
strcpy(reason, english(1968)); /* evaluate to apply the divergence test */
currentline = get_currentline();
pushpending(t,currentline); /* push the integral, not the whole current line */
return 0;
}
/*_____________________________________________________________________*/
static int select_limitcomparison_arg(term u, term n, term *ans)
/* find a term, *ans, such that lim(n->infinity, u/*ans) is finite
and nonzero, and the sum of *ans is easier than the sum of u.
*/
{ term c, deg, logdeg, algpart, logpart;
int err;
err = log_leading_term(u,n,infinity,&c,°,&logdeg);
if(err)
return 1;
if((OBJECT(c) && !ZERO(c)) || !infer(nonzero(c)))
{ if(ZERO(deg))
algpart = one;
else if(NEGATIVE(deg))
algpart = reciprocal(make_power(n,ARG(0,deg)));
else
algpart = make_power(n,deg);
if(ZERO(logdeg))
logpart = one;
else if(NEGATIVE(logdeg))
logpart = reciprocal(make_power(ln1(n),ARG(0,logdeg)));
else
logpart = make_power(ln1(n),logdeg);
*ans = ONE(algpart) ? logpart : ONE(logpart) ? algpart : product(algpart,logpart);
return 0;
}
return 1;
}
/*_______________________________________________________*/
static int varexp(term t, term n)
/* return 1 if t contains n in an exponent */
{ unsigned short m;
int i;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^')
return (contains(ARG(1,t),FUNCTOR(n)) || varexp(ARG(0,t),n));
m = ARITY(t);
for(i=0;i<m;i++)
{ if(varexp(ARG(i,t),n))
return 1;
}
return 0;
}
/*_______________________________________________________*/
static term upper_comparison(term u, term n, term lo)
/* find a term ans such that |u| <= |ans|.
This is used in the comparison test to prove convergence. If you can't do better
return u itself.
*/
/* Example: if u = 1/n^n we want ans = 1/2^n */
{ unsigned short f;
term v,w,q,num,denom,ans;
int savelogflag = get_polyvallogflag();
POLYnomial p;
term c,c2,deg,deg2,logdeg,logdeg2;
int i,err,m;
double zdeg, zdeg2, zlogdeg,zlogdeg2,z;
if(NEGATIVE(u))
u = ARG(0,u);
f = FUNCTOR(u);
if(ATOMIC(u))
return u;
if(f == ATAN)
return make_fraction(pi,two);
if(f == TANH)
return one;
if(f == ASIN)
return make_fraction(pi,two);
if(f == ACOS)
return pi;
if(f == SIN || f == TAN)
{ err = limval(limit(arrow(n,infinity),ARG(0,u)),&v);
if(!err && ZERO(v))
return upper_comparison(ARG(0,u),n,lo);
return one;
}
if(f == COS)
return one;
set_polyvallogflag(1);
if(FRACTION(u))
{ num = upper_comparison(ARG(0,u),n,lo);
denom = lower_comparison(ARG(1,u),n,lo);
if(varexp(denom,n))
/* watch out for the case polynomial/2^n */
/* FIX THIS--it's wrong */
{ q = lower_comparison(denom,n,lo);
err = series_check(lessthan(one,num),n);
if(!err)
{ polyval1(reciprocal(q),&ans);
set_polyvallogflag(savelogflag);
return ans;
}
err = limval(limit(arrow(n,infinity),num),&w);
if(!err && !NOTDEFINED(w) && !series_check(lessthan(zero,w),n))
{ w = make_fraction(w,two);
err = series_check(lessthan(num,w),n);
if(!err)
{ polyval1(make_fraction(w,q),&ans);
set_polyvallogflag(savelogflag);
return ans;
}
}
}
/* We get here with e.g. ln(n)/n^2 */
/* Now check the for the case when the denom is asymptotic to n^s for s > 1 */
if( !log_leading_term(denom,n,infinity,&c,°,&logdeg) &&
!log_leading_term(num,n,infinity,&c2,°2,&logdeg2) &&
(!ZERO(logdeg) || !ZERO(logdeg2)) &&
!deval(deg,&zdeg) &&
!deval(deg2,&zdeg2) &&
!deval(logdeg,&zlogdeg) &&
!deval(logdeg2,&zlogdeg2) &&
zdeg != BADVAL && zdeg2 != BADVAL &&
zlogdeg != BADVAL && zlogdeg2 != BADVAL
)
{ z = zdeg-zdeg2;
if(z > 1.0)
{ /* Then the series converges. */
if( z - zlogdeg2 > 1.0)
/* Then just replace the log terms by n */
{ w = product(make_fraction(c2,c),make_power(n,sum(sum(deg2,tnegate(deg)),logdeg2))),
polyval1(w,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
}
}
v = make_fraction(num,denom);
polyval1(v,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
if(f == '+')
{ err = makepoly(u,n,&p);
if(!err)
{ /* bound on a polynomial is the sum of the coefficients times
the leading term; */
deg = make_int(ARITY(p)-1);
SETFUNCTOR(p,'+',ARITY(p));
polyval1(p,&c);
polyval1(product(c,make_power(n,deg)),&ans);
set_polyvallogflag(savelogflag);
return ans;
}
}
if(f == '^')
{ v = make_power(upper_comparison(ARG(0,u),n,lo),upper_comparison(ARG(1,u),n,lo));
polyval1(v,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
m = ARITY(u);
if(f == '*')
{ v = make_term('*',(unsigned short)m);
for(i=0;i<m;i++)
ARGREP(v,i,upper_comparison(ARG(i,u),n,lo));
polyval1(v,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
if(f == LN || f == SQRT || f == COSH || f == SINH || f == TANH)
{ ans = make_term(f,1);
ARGREP(ans,0,upper_comparison(ARG(0,u),n,lo));
set_polyvallogflag(savelogflag);
return ans;
}
if(f == LOG || f == ROOT)
{ ans = make_term(f,2);
ARGREP(ans,0,ARG(0,u));
ARGREP(ans,1,upper_comparison(ARG(1,u),n,lo));
set_polyvallogflag(savelogflag);
return ans;
}
set_polyvallogflag(savelogflag);
return u;
}
/*_______________________________________________________*/
static term lower_comparison(term u, term n, term lo)
/* find a term ans such that for sufficiently large values of n
we have|ans| <= |u|, to use in the divergence
comparison test, or in the denominator when using the comparison
test to prove convergence.
If you can't do better return u itself.
Example: 1/n^n converges because 2^n <= n^n
*/
{ unsigned short f,m;
term v,w,num,denom,ans,q,r;
POLYnomial p;
term deg;
int i,err,savelogflag;
if(NEGATIVE(u))
u = ARG(0,u);
f = FUNCTOR(u);
if(ATOMIC(u))
return u;
if(f == ASEC || f == ACSC)
return one;
savelogflag = get_polyvallogflag();
set_polyvallogflag(1);
if(f == SIN || f == TAN)
{ err = limval(limit(arrow(n,infinity),ARG(0,u)),&v);
if(!err && ZERO(v))
{ v = lower_comparison(ARG(0,u),n,lo);
polyval1(make_fraction(v,two),&ans);
set_polyvallogflag(savelogflag);
return ans;
}
}
if(f == COS)
{ err = limval(limit(arrow(n,infinity),ARG(0,u)),&v);
if(!err && ZERO(v))
{ err = series_check(lessthan(ARG(0,u),make_fraction(pi,three)),n);
set_polyvallogflag(savelogflag);
return err ? u: make_fraction(one,two);
}
}
if(FRACTION(u))
{ num = ARG(0,u);
denom = ARG(1,u);
v = make_fraction(lower_comparison(num,n,lo),upper_comparison(denom,n,lo));
polyval1(v,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
if(f == '+')
{ err = makepoly(u,n,&p);
if(!err)
{ /* lower bound on a polynomial is half the leading term */
/* but lo must be greater than the twice the sum of the other
coefficients divided by the leading coefficient. We don't care
about that here though.
*/
deg = make_int(ARITY(p)-1);
v = make_fraction(product(ARG(ARITY(p)-1,p),make_power(n,deg)),two);
polyval1(v,&ans);
// SETFUNCTOR(p,'+',ARITY(p));
// polyval1(make_fraction(product(two,p),ARG(ARITY(p)-1,p)),&c);
return ans;
}
}
if(f == '^')
{ r = ARG(0,u);
q = ARG(1,u);
if(contains(q,FUNCTOR(n)))
{ /* example, u = n^n, we want to get 2^n */
err = limval(limit(arrow(n,infinity),r),&w);
if(err)
return u;
err = infer(lessthan(two,w));
if(err)
return u;
v = make_power(two,lower_comparison(q,n,lo));
polyval1(v,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
/* Now the exponent is constant */
v = make_power(lower_comparison(r,n,lo),q);
polyval1(v,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
m = ARITY(u);
if(f == '*')
{ v = make_term('*',m);
for(i=0;i<m;i++)
ARGREP(v,i,lower_comparison(ARG(i,u),n,lo));
polyval1(v,&ans);
set_polyvallogflag(savelogflag);
return ans;
}
if(f == LN || f == SQRT || f == COSH || f == SINH || f == TANH)
{ ans = make_term(f,1);
ARGREP(ans,0,lower_comparison(ARG(0,u),n,lo));
set_polyvallogflag(savelogflag);
return ans;
}
if(f == LOG || f == ROOT)
{ ans = make_term(f,2);
ARGREP(ans,0,ARG(0,u));
ARGREP(ans,1,lower_comparison(ARG(1,u),n,lo));
set_polyvallogflag(savelogflag);
return ans;
}
set_polyvallogflag(savelogflag);
return u;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int limitcomparisontest(term t, term arg, term *next, char *reason)
/* set up the limit to evaluate for the limit comparison test */
/* arg is the general term of the comparison series */
{ term u,n;
int err, currentline;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
/* series that start from -infinity need to be changed to this kind first */
if(FUNCTOR(arg) == ILLEGAL)
{ return 1; /* FINISH THIS */
}
n = ARG(1,t); /* summation variable */
if(!contains(arg,FUNCTOR(n)))
{ errbuf(0,english(2272));
/* The comparison term does not contain the summation variable. */
return 1;
}
if(FUNCTOR(arg) == ILLEGAL)
{ err = select_limitcomparison_arg(u,n,&arg);
if(err)
return 1;
}
*next = limit(arrow(n,infinity),make_fraction(u,arg));
strcpy(reason, english(2273)); /* evaluate to apply the limit comparison test */
currentline = get_currentline();
pushpending(t,currentline); /* push the integral, not the whole current line */
return 0;
}
/*________________________________________________________________*/
static int eliminate_trig(term u, term *ans)
/* eliminate factors which are trig functions, or roots or
powers or ABS of trig functions. Return 0 for success, 1 for
failure; on success the result is written to *ans.
*/
{ unsigned short n,f;
int i,k;
term v,temp;
if(FRACTION(u) && !eliminate_trig(ARG(0,u),&v))
{ *ans = make_fraction(v,ARG(1,u));
return 0;
}
f = FUNCTOR(u);
if(TRIGFUNCTOR(f))
{ *ans = ARG(0,u);
return 0;
}
if((f == '^' || f == SQRT || f == ABS) && TRIGFUNCTOR(FUNCTOR(ARG(0,u))))
{ *ans = ARG(0,ARG(0,u));
return 0;
}
if(f == ROOT && TRIGFUNCTOR(FUNCTOR(ARG(1,u))))
{ *ans = ARG(0,ARG(1,u));
return 0;
}
if(f != '*')
return 1;
n = ARITY(u);
*ans = make_term(n,'*');
k=0;
for(i=0;i<n;i++)
{ v = ARG(i,u);
if(!eliminate_trig(v,&temp))
{ ARGREP(*ans,i,temp);
++k;
}
else
ARGREP(*ans,i,v);
}
if(k==0)
{ RELEASE(*ans);
return 1;
}
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int comparisontest1(term t, term arg, term *next, char *reason)
/* set up the new series to evaluate for convergence */
/* arg is the general term of the comparison series */
{ term u,n,ineq,lo,c,deg;
int currentline,err;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
/* series that start from -infinity need to be changed to this kind first */
n = ARG(1,t); /* summation variable */
lo = ARG(2,t);
if(FUNCTOR(arg) == ILLEGAL)
{ /* automode, try to select a good comparison function */
arg = upper_comparison(u,n,lo);
if(equals(arg,u))
return 1;
/* Try to determine if this is going to work */
err = leading_term(arg,n,infinity,&c,°);
if(!err)
{ err = check(le(minusone,deg));
if(!err)
return 1; /* comparison series definitely diverges */
}
}
if(!contains(arg,FUNCTOR(n)))
{ errbuf(0,english(2272));
/* The comparison term does not contain the summation variable. */
return 1;
}
if(obviously_nonnegative(u))
ineq = le(u,arg);
else
ineq = le(abs1(u),arg);
assume(le(lo,n)); /* this assumption may be needed while solving the inequality */
/* it will be removed by finishcomparisontest1.*/
unbindvar(n);
*next = le(u,arg);
HIGHLIGHT(*next);
strcpy(reason, english(2259)); /* comparison test */
currentline = get_currentline();
pushpending(t,currentline);
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int comparisontest2(term t, term arg, term *next, char *reason)
/* set up the new series to evaluate for divergence */
/* arg is the general term of the comparison series */
/* *next will come out as an inequality to verify */
{ term u,n,ineq,lo,c,deg;
int currentline,err;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
/* series that start from -infinity need to be changed to this kind first */
n = ARG(1,t); /* summation variable */
lo = ARG(2,t);
if(FUNCTOR(arg) == ILLEGAL)
{ /* automode, try to select a good comparison function */
arg = lower_comparison(u,n,lo);
if(equals(arg,u))
return 1;
/* Try to determine if this is going to work */
err = leading_term(arg,n,infinity,&c,°);
if(!err)
{ err = check(lessthan(deg,minusone));
if(!err)
return 1; /* comparison series definitely converges */
}
}
if(!contains(arg,FUNCTOR(n)))
{ errbuf(0,english(2272));
/* The comparison term does not contain the summation variable. */
return 1;
}
if(obviously_nonnegative(u))
ineq = le(u,arg);
else
ineq = le(abs1(u),arg);
assume(le(lo,n)); /* this assumption may be needed while solving the inequality */
/* it will be removed by finishcomparisontest1. */
unbindvar(n);
*next = le(arg,u);
HIGHLIGHT(*next);
strcpy(reason, english(2259)); /* comparison test */
currentline = get_currentline();
pushpending(t,currentline); /* push the integral, not the whole current line */
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int condensationtest(term t, term arg, term *next, char *reason)
/* set up the new series to evaluate for convergence */
{ term u,n,v,w,bound;
int currentline,err;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(0,t);
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
/* series that start from -infinity need to be changed to this kind first */
n = ARG(1,t); /* summation variable */
err = eventually_decreasing(u,n,ARG(2,t),&bound);
if(err)
{ errbuf(0,english(2260));
/* The general term is not decreasing */
return 1;
}
subst(make_power(two,n),n,u,&v);
w = product(make_power(two,n),v);
*next = indexedsum(w,n,ARG(2,t),ARG(3,t));
HIGHLIGHT(*next);
strcpy(reason,english(2294)); /* condensation test */
currentline = get_currentline();
pushpending(t,currentline);
return 0;
}
/*_____________________________________________________________________*/
static int ok_ineq(term t, term n, term *c)
/* return 1 if t has the form c < n or c <= n or the equivalent,
or if t is a disjunction, one of whose terms has that form.
*/
{ unsigned short f = FUNCTOR(t);
unsigned short m;
int i;
if(
(f == LE || f == '<' || f == NE) &&
equals(ARG(1,t),n) &&
!contains(ARG(0,t),FUNCTOR(n))
)
{ *c = ARG(0,t);
return 1;
}
if
(
(f == GE || f == '>' || f == NE) &&
equals(ARG(0,t),n) &&
!contains(ARG(1,t),FUNCTOR(n))
)
{ *c = ARG(1,t);
return 1;
}
if(f == OR)
{ m = ARITY(t);
for(i=0;i<m;i++)
{ if(ok_ineq(ARG(i,t),n,c))
return 1;
}
}
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishcomparisontest1(term t, term arg, term *next, char *reason)
/* t is the final form of the inequality generated by comparisontest1. The next line
must be a series, formed from the right side of the original inequality, which must be
fished out of the history list. If the test was inconclusive (the equality is not
verified) the next line is the original series.
This operator has to remove the assumption lo <= n which was made by
comparisontest1, and any other assumptions that contain the bound variable n,
made while solving the inequality, but assumptions NOT containing n should
be retained, because the validity of the inequality may depend on them!
*/
{ int err;
term u,n,v,prev,c;
int oldline;
term mterm;
double z;
oldline = used4(comparisontest1);
if(oldline == 0)
return 1;
err = readpending(&u);
if(err)
return 1;
if(FUNCTOR(u) != SUM || !equals(ARG(3,u),infinity))
assert(0);
n = ARG(1,u);
if(!ISATOM(n))
assert(0);
if(equals(t,true))
{ *next = u;
mterm = ARG(2,u);
goto success;
}
if(equals(t,false))
{ commentbuf(0,english(2265));
/* !The test was inconclusive. */
*next = u;
goto out;
}
/* Now, t might for example be n > 4; but the only way
we can succeed now is if t has the form c < n, or n > c,
or c <= n, or n >= c. */
if(!ok_ineq(t,n,&c))
return 1;
err = poppending(&u);
if(err)
return 1;
err = infer(le(c,ARG(2,u)));
if(!err)
{ mterm = ARG(2,u);
goto success;
}
if(isinteger(c))
{ mterm = c;
goto success;
}
if(seminumerical(c))
{ deval(c,&z);
if(z < 1.0e9)
{ mterm = make_int((long) z);
goto success;
}
}
goto out;
success:
/* convergence of the original series is reduce to convergence of a new series */
prev = history(oldline);
if(FUNCTOR(prev) != LE)
assert(0);
copy(ARG(1,prev),&v);
*next = indexedsum(v,ARG(1,u),mterm,infinity);
commentbuf(0,english(2312));
/* !If this series converges, so does the original series. */
out:
remove_dependent_assumptions(n);
strcpy(reason, english(2269)); /* finish comparison test */
bindvar(n);
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishcomparisontest2(term t, term arg, term *next, char *reason)
/* t is the final form of the inequality generated by comparisontest2. The next line
must be a series, formed from the right side of the original inequality, which must be
fished out of the history list. If the test was inconclusive (the equality is not
verified) the next line is the original series.
This operator has to remove the assumption lo <= n which was made by
comparisontest2, and any other assumptions that contain the bound variable n,
made while solving the inequality, but assumptions NOT containing n should
be retained, because the validity of the inequality may depend on them!
*/
{ int err;
term u,n,v,prev,c;
int oldline;
term mterm;
double z;
oldline = used4(comparisontest2);
if(oldline == 0)
return 1;
err = readpending(&u);
if(err)
return 1;
if(FUNCTOR(u) != SUM || !equals(ARG(3,u),infinity))
assert(0);
n = ARG(1,u);
if(!ISATOM(n))
assert(0);
if(equals(t,true))
{ *next = u;
mterm = ARG(2,u);
goto success;
}
if(equals(t,false))
{ commentbuf(0,english(2265));
/* !The test was inconclusive. */
*next = u;
goto out;
}
/* Now, t might for example be n > 4; but the only way
we can succeed now is if t has the form c < n, or n > c,
or c <= n, or n >= c. */
if(!ok_ineq(t,n,&c))
return 1;
err = poppending(&u);
if(err)
return 1;
err = infer(le(c,ARG(2,u)));
if(!err)
{ mterm = ARG(2,u);
goto success;
}
if(isinteger(c))
{ mterm = c;
goto success;
}
if(seminumerical(c))
{ deval(c,&z);
if(z < 1.0e9)
{ mterm = make_int((long) z);
goto success;
}
}
goto out;
success:
/* divergence of the original series is reduce to divergence of a new series */
prev = history(oldline);
if(FUNCTOR(prev) != LE)
assert(0);
copy(ARG(0,prev),&v);
*next = indexedsum(v,ARG(1,u),mterm,infinity);
commentbuf(0,english(2313));
/* !If this series diverges, so does the original series. */
out:
remove_dependent_assumptions(n);
strcpy(reason, english(2269)); /* finish comparison test */
bindvar(n);
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishintegraltest(term t, term arg, term *next, char *reason)
/* Restore the original series which was left pending and state
the conclusion. This operation can only be applied at toplevel. */
{ int err,nvars;
long m;
char buffer[128];
term *atomlist;
term lo,extra,bound,u,n;
int convergence;
double z;
if(!used4(integraltest))
return 1;
if(!equals(t,history(get_currentline())))
return 1; /* works only at toplevel */
err = poppending(&u);
if(err)
return 1;
if(ISINFINITE(t) || equals(t,undefined))
/* if divergent, the integral must be infinite, but maybe Mathpert only finds 'undefined' */
{ *next = equation(u,t);
convergence = 0;
goto out;
}
else if(!contains_calc(t))
{ lo = ARG(2,u);
n = ARG(1,u);
if(!ISINTEGER(lo))
{ *next = le(u,infinity);
convergence = 1;
goto out;
}
err = eventually_decreasing(ARG(0,u),n,ARG(2,u),&bound);
if(err)
bound = infinity;
if(equals(bound,infinity) || !seminumerical(bound))
{ *next = lessthan(u,infinity);
convergence = 1;
goto out;
}
deval(bound,&z);
if(z == BADVAL || fabs(z) > 100.00)
{ *next = lessthan(u,infinity);
convergence = 1;
goto out;
}
if(!nearint(z,&m))
m = (long) floor(z) + 1;
if(m <= INTDATA(lo))
{ subst(lo,n,ARG(0,u),&extra);
*next = lessthan(u,sum(t,extra));
convergence = 1;
goto out;
}
extra = indexedsum(ARG(0,u),n,lo,make_int(m));
*next = lessthan(u,sum(t,extra));
convergence = 1;
}
else
return 1;
out:
if(convergence)
strcpy(buffer,english(2262)); /* !The series is convergent */
else
strcpy(buffer, english(2263)); /* !The series is divergent */
nvars = variablesin(u,&atomlist);
free2(atomlist);
if(nvars > 1 && get_nextassumption() > 0)
strcat(buffer, english(2264));
/* Some assumptions have been made. */
commentbuf(0,buffer);
strcpy(reason,english(2266)); /* finish integral test */
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishroottest(term t, term arg, term *next, char *reason)
/* Restore the original series which was left pending and state
the conclusion. This operation can only be applied at toplevel. */
{ int err;
term u;
char buffer[128];
int oldline = used4(roottest);
if(!oldline)
return 1;
if(!equals(t,history(get_currentline())))
return 1; /* works only at toplevel */
if(contains(t,LIMIT))
{ errbuf(0, english(2271));
/* You must first evaluate the limit, or undo. */
return 1;
}
if(contains(t,INTEGRAL))
return 1; /* assert(0) */
err = poppending(&u);
if(FUNCTOR(u) != SUM)
assert(0);
if(err)
return 1;
strcpy(reason, english(2267)); /* finish root test */
if(ONE(t))
{ *next = history(oldline);
commentbuf(0, english(2265));
/* The test was inconclusive */
return 0;
}
err = infer(lessthan(t,one));
if(!err)
{ strcpy(buffer, english(2262));
/* the series is convergent */
goto out;
}
err = infer(lessthan(one,t));
if(!err)
{ strcpy(buffer, english(2263));
/* the series is divergent */
goto out;
}
err = infer(le(one,t));
if(!err)
{ strcpy(buffer, english(2265));
/* The test was inconclusive */
*next = history(oldline);
return 0;
}
assume(lessthan(t,one));
strcpy(buffer, english(2262)); /* The series is convergent */
strcat(buffer, english(2264)); /* Some assumptions have been made */
out:
*next = history(oldline);
commentbuf(0,buffer);
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishratiotest(term t, term arg, term *next, char *reason)
/* Restore the original series which was left pending and state
the conclusion. This operation can only be applied at toplevel. */
{ int err;
term u;
char buffer[128];
int oldline = used4(ratiotest);
if(!oldline)
return 1;
if(!equals(t,history(get_currentline())))
return 1; /* works only at toplevel */
if(contains(t,LIMIT))
{ errbuf(0, english(2271));
/* You must first evaluate the limit, or undo. */
return 1;
}
if(contains(t,INTEGRAL))
return 1; /* assert(0) */
err = poppending(&u);
if(err)
return 1;
strcpy(reason, english(2268)); /* finish ratio test */
if(ONE(t))
{ *next = history(oldline-1);
commentbuf(0, english(2265));
/* The test was inconclusive */
return 0;
}
err = infer(lessthan(t,one));
if(!err)
{ strcpy(buffer, english(2262));
/* the series is convergent */
goto out;
}
err = infer(lessthan(one,t));
if(!err)
{ strcpy(buffer, english(2263));
/* the series is divergent */
goto out;
}
err = infer(le(one,t));
if(!err)
{ strcpy(buffer, english(2265));
/* The test was inconclusive */
*next = u;
return 0;
}
assume(lessthan(t,one));
strcpy(buffer, english(2262)); /* The series is convergent */
strcat(buffer, english(2264)); /* Some assumptions have been made */
out:
copy(history(oldline-1),next);
SETCONVERGENT(*next);
commentbuf(0,buffer);
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishdivergencetest(term t, term arg, term *next, char *reason)
/* Restore the original series which was left pending and state
the conclusion. This operation can only be applied at toplevel. */
{ int err;
term u;
char buffer[128];
int oldline = used4(divergencetest);
if(!oldline)
return 1;
if(!equals(t,history(get_currentline())))
return 1; /* works only at toplevel */
if(contains(t,LIMIT))
{ errbuf(0, english(2271));
/* You must first evaluate the limit, or undo. */
return 1;
}
if(contains(t,INTEGRAL))
return 1; /* assert(0) */
err = poppending(&u);
if(err)
return 1;
strcpy(reason, english(2270)); /* finish divergence test */
if(ZERO(t))
{ *next = history(oldline);
commentbuf(0, english(2265));
/* The test was inconclusive */
return 0;
}
err = infer(lessthan(zero,t));
if(!err)
{ commentbuf(0, english(2263));
/* !The series is divergent */
*next = equation(u,infinity);
return 0;
}
err = infer(lessthan(t,zero));
if(!err)
{ commentbuf(0, english(2263));
/* !The series is divergent */
*next = equation(u,minusinfinity);
return 0;
}
err = infer(equation(t,zero));
if(!err)
{ commentbuf(0,english(2265));
/* !The test is nonconclusive */
*next = u;
return 0;
}
assume(nonzero(t));
*next = equation(u,undefined);
strcpy(buffer, english(2263)); /* !The series is divergent */
strcat(buffer, english(2264)); /* Some assumptions have been made */
commentbuf(0,buffer);
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishlimitcomparisontest(term t, term arg, term *next, char *reason)
/* Restore the original series which was left pending and state
the conclusion. This operation can only be applied at toplevel. */
{ int err,nvars;
term *atomlist;
term u,v;
char buffer[128];
int startline = used4(limitcomparisontest);
if(!startline)
return 1;
if(!equals(t,history(get_currentline())))
return 1; /* works only at toplevel */
if(contains(t,LIMIT))
{ errbuf(0, english(2271));
/* You must first evaluate the limit, or undo. */
return 1;
}
if(contains(t,INTEGRAL))
return 1; /* assert(0) */
err = poppending(&u);
if(err)
return 1;
if(FUNCTOR(u) != SUM)
return 1; /* assert(0) */
strcpy(reason, english(2274)); /* finish limit comparison test */
if(ZERO(t) || ISINFINITE(t) || series_check(nonzero(t), ARG(1,u)))
{ *next = u;
strcpy(buffer, english(2265));
/* The test was inconclusive. */
return 0;
}
strcpy(buffer,english(2275));
/* The test worked; the problem is reduced to the convergence of this series. */
nvars = variablesin(u,&atomlist);
free2(atomlist);
if(nvars > 1 && get_nextassumption() > 0)
strcat(buffer, english(2264));
/* Some assumptions have been made. */
commentbuf(0,buffer);
/* Now we still have to construct the new series */
v = history(startline); /* this is the limit term created when the test began */
if(FUNCTOR(v) != LIMIT)
return 1; /* assert(0) */
if(!FRACTION(ARG(0,v)))
return 1; /* assert(0) */
*next = sigma(ARG(1,v),ARG(1,u),ARG(2,u),ARG(3,u));
return 0;
}
/*_____________________________________________________________________*/
static int contains_undefined(term t)
/* return 1 if t contains a NOTDEFINED functor */
{ unsigned short n;
int i;
if(ISATOM(t))
return NOTDEFINED(t);
if(OBJECT(t))
return 0;
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_undefined(ARG(i,t)))
return 1;
}
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_SERIES int finishcondensationtest(term t, term arg, term *next, char *reason)
/* Restore the original series which was left pending and state
the conclusion. This operation can only be applied at toplevel. */
{ int err;
term u;
int startline = used4(condensationtest);
if(!startline)
return 1;
if(!equals(t,history(get_currentline())))
return 1; /* works only at toplevel */
if(contains(t,LIMIT))
{ errbuf(0, english(2271));
/* You must first evaluate the limit, or undo. */
return 1;
}
if(contains(t,INTEGRAL))
return 1; /* assert(0) */
err = poppending(&u);
if(err)
return 1;
strcpy(reason, english(2295)); /* finish condensation test */
*next = history(startline-1);
if(
(FUNCTOR(t) == '<' && equals(ARG(1,t),infinity)) ||
(!contains(t,SUM) && !contains_calc(t) && !contains_undefined(t))
)
{ if(get_nvariables() > 1)
commentbuf(0, english(2296));
/* !The test worked. The series is convergent.
Assumptions may have been made. */
else
commentbuf(0, english(2297));
/* !The test worked. The series is convergent. */
}
else if(FUNCTOR(t) == '=' && NOTDEFINED(ARG(1,t)))
commentbuf(0, english(2298));
/* !The test worked. The series is divergent. */
else
commentbuf(0, english(2265));
/* !The test was inconclusive. */
if(FUNCTOR(*next) == SUM)
SETCONVERGENT(*next);
return 0;
}
/*____________________________________________________*/
MEXPORT_SERIES int evalfirstterms(term t, term arg, term *next, char *reason)
/* calculate sum of the first few terms */
/* arg is the number of terms to be summed */
{ double z;
int err;
term lo,n,b,u,finitesum,v,w;
long k,m,m2;
if(FUNCTOR(t) != SUM || ARITY(t) < 4)
return 1;
if(!equals(ARG(3,t),infinity))
return 1; /* this is only for infinite series */
if(equals(ARG(2,t),minusinfinity))
return 1;
lo = ARG(2,t);
if(!ISINTEGER(lo))
return 1;
n = ARG(1,t); /* summation variable */
u = ARG(0,t); /* general term of the sum */
k = INTDATA(lo);
if(!ISINTEGER(arg))
return 1;
m = INTDATA(arg);
if(m > 0x000ffffL)
{ errbuf(0,english(2309));
/* Maximum number of first terms to be added is about 128,000. */
return 1;
}
if(k > 0x00ffffffL)
{ errbuf(0, english(2310));
/* Lower index of sum cannot exceed sixteen million */
return 1;
}
b = make_int(m+k-1); /* no overflow */
finitesum = indexedsum(u,n,lo,b);
err = deval(finitesum,&z);
if(z == BADVAL)
{ errbuf(0,dem(err));
return 1;
}
if(ARITY(t) == 4)
*next = sum(make_double(z),indexedsum(u,n,make_int(m+k),infinity));
else
{ v = ARG(4,t);
if(NEGATIVE(v))
/* general term not showing */
m2 = INTDATA(ARG(0,v));
else
m2 = INTDATA(v);
/* m2 is the number of terms that were showing */
if(m2 > m + 2)
w = make_int(m2-m);
else
w = two;
*next = sum(make_double(z),ldots(u,n,make_int(m+k),infinity,w));
}
strcpy(reason, english(2308)); /* calculate first terms */
return 0;
}
/*______________________________________________________________________*/
static void remove_dependent_assumptions(term n)
/* remove all assumptions containing n or variables that depend on n.
Actually, the assumptions can't really be removed or undo won't work;
instead we push 'true' on the linked list of assumptions.
*/
{ assumption **assumptions = get_assumptions();
int nextassumption = get_nextassumption();
int i;
term u;
if(!ISATOM(n))
return;
for(i=0;i<nextassumption;i++)
{ u = assumptions[i]->prop;
if(depends(u,n))
push_assumption(true,i);
}
}
/*________________________________________________________________________*/
MEXPORT_SERIES int statefinalbound1(term t, term arg, term *next, char *reason)
/* After the comparison test has reduced the problem to a second series,
and that series has been proved convergent or divergent, state the
final resulting bound, original series <= current line
*/
{ int oldline,i;
oldline = used4(finishcomparisontest1);
if(oldline == 0)
return 1;
i = used3(comparisontest1, oldline-1);
if(i==0)
return 1;
*next = le(history(i-1),t);
if(FUNCTOR(ARG(0,*next)) != SUM)
return 1;
PROTECT(ARG(0,*next));
strcpy(reason, english(2403)); /* result of comparison test */
commentbuf(0,english(2262)); /* !The series is convergent */
return 0;
}
/*________________________________________________________________________*/
MEXPORT_SERIES int statefinalbound2(term t, term arg, term *next, char *reason)
/* After the comparison test has reduced the problem to a second series,
and that series has been proved convergent or divergent, state the
final resulting bound, original series <= current line
*/
{ int oldline,i;
oldline = used4(finishcomparisontest2);
if(oldline == 0)
return 1;
i = used3(comparisontest2, oldline-1);
if(i==0)
return 1;
if(!NOTDEFINED(t))
return 1;
*next = equation(history(i-1),t);
if(FUNCTOR(ARG(0,*next)) != SUM)
return 1;
PROTECT(ARG(0,*next));
strcpy(reason, english(2403)); /* result of comparison test */
commentbuf(0,english(2263)); /* !The series is divergent */
return 0;
}
/*________________________________________________________________________*/
MEXPORT_SERIES int harmonicseries(term t, term arg, term *next, char *reason)
/* the harmonic series = infinity */
{ term n,u,v,c,denom;
if(FUNCTOR(t) != SUM || !equals(ARG(3,t),infinity))
return 1;
n = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) == '^' && equals(ARG(1,u),minusone))
denom = ARG(0,u);
else if(FRACTION(u) && !depends(ARG(0,u),n))
denom = ARG(1,u);
else
return 1;
if(FUNCTOR(denom) == '*')
twoparts(denom,n,&c,&v);
else
v = denom;
if(!equals(v,n))
return 1;
*next = infinity;
strcpy(reason, "$$sum(1/k,k,1,infinity) = infinity$$");
/* We don't even need to check the lower limit of the sum.
We don't adjust the reason string for the lower limit,
since this way it matches the menu text. */
return 0;
}
/*________________________________________________________________________*/
MEXPORT_SERIES int zeta2(term t, term arg, term *next, char *reason)
/* Zeta(2) = pi^2/6 */
{ term n,u,lo;
if(FUNCTOR(t) != SUM || !equals(ARG(3,t),infinity))
return 1;
n = ARG(1,t);
u = ARG(0,t);
lo = ARG(2,t);
if(!FRACTION(u) || !ONE(ARG(0,u)) ||
FUNCTOR(ARG(1,u)) != '^' ||
!equals(ARG(1,ARG(1,u)),two) ||
!equals(ARG(0,ARG(1,u)),n)
)
return 1;
if(ONE(lo))
*next = make_fraction(make_power(pi,two),six);
else if(ISINTEGER(lo) && INTDATA(lo) > 1)
*next = sum(make_fraction(make_power(pi,two),six),tnegate(indexedsum(u,n,one,make_int(INTDATA(lo)-1))));
else
return 1;
strcpy(reason, "$$sum(1/k^2,k,1,infinity) = pi^2/6$$");
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists