Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/series/
Upload File :
Current File : /usr/home/beeson/MathXpert/series/series.c

/* infinite series */
/*
2.6.92 original date
1.21.99 last modified
9.2.04 added get_new_fname, which used to be in userfunc.c
9.8.11  cast return value of strlen to int for 64-bit compilation
5.1.13  wrote first_terms_aux and code that calls it.
        modified seriesmoreterms and seriessubindex to work on sums as well as series (in automode)
        corrected lnseries and lnseriesminus
5.1.13  replaced getnewindexvar with getindexvar
5.2.13  corrected lnseries, lnseries2, lnseries3.
        modified seriessubindex to select its arg in automode
5.10.13  modified restriction on seriesintdif and seriesintdifdef that they only work on the whole current line.
        Now they can work on the non-constant part if the currentline is a product of a constant times something else.
5.15.13  Added tanseries, tanseries2, tanseries3.
5.21.13  corrected is_power_series and added an assert(0) in intseries
         corrected eliminatecofi so it doesn't return an undefined term,  but takes a limit if necessary,
         so it can deal with expanding  ln(sin(x)/x) in a power series.
5.28.13  corrected seriesbernoulli2 and seriesbernoulli3, and seriescot2 and seriescot3, where they still called seriestan.
         added code to check the domain in seriesatan, seriessec, etc.
         changed OEM summation character to \\sigma in several places
5.31.13  corrected seriesaddindex not to pass tengate(illegal).
         improved seriessubindex to handle an exponent like 2k-2  or even 2k-4.
         corrected seriessubindex operating on a sum
6.11.13  made seriesmoreterms work on a single series in automode under ADDSERIES
1.5.15   removed illegal characters
1.9.25   corrected seriesmoreterms to allow lo to be 1 and accept any fraction or power as summand
2.16.25  edited tanseries to use twon
         removed unused 'nminusone'  in bernoulliseries
         removed unused 'b' in seriesmoreterms.
2.18.25  removed unused 'savei' in seriesmoreterms. 
*/

#include <string.h>
#include <assert.h>

#include "globals.h"
#include "series.h"
#include "match.h"
#include "prover.h"  /*  getnewindexvar */
#include "symbols.h"
#include "errbuf.h"
#include "psubst.h"
#include "pvalaux.h"  /* twoparts */
#include "ssolve.h"
#include "userfunc.h"
#include "deval.h"
#include "order.h"     /* numerical */
#include "probtype.h"  /* get_problemtype, POWERSERIES */
#include "pathtail.h"  /* set_pathtail */
#include "autosimp.h"  /* SetShowStepOperation */
#include "series.h"
#include "polynoms.h"  /* ispolyin */
#include "pstring.h"   /* log_term */

/*________________________________________________________________*/
int oneminusxseries(term t, term arg, term *next, char *reason)
{ int flag=0;
  term a,temp,denom;
  int err;
  term n;
  short savenextassumption = get_nextassumption();
  if(!FRACTION(t))
     return 1;
  denom = ARG(1,t);
  if(FUNCTOR(denom) != '+' || ARITY(denom) != 2)
     return 1;
  temp = make_fraction(one,sum(one,tnegate(var0)));
  err = unify1(temp,t,&a,&flag);
  if(err)
     { RELEASE(ARG(1,temp));
       RELEASE(temp);
       return 1;
     }
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  err = check1(lessthan(abs1(a),one));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  err = infer(equation(a,zero));
  if(!err)
     { errbuf(0,english(2326));  /* The resulting series would converge only at isolated points */
       set_nextassumption(savenextassumption);
       return 1;
     }
  *next = sigma(make_power(a,n),n,zero,infinity);
  HIGHLIGHT(*next);
  strcpy(reason,"$$1/(1-x) = sum(x^n,n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int oneminusxseries2(term t, term arg, term *next, char *reason)
/* 1/(1-x) = ...  with 3 terms and ldots */
{ term temp;
  int err = oneminusxseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"$1/(1-x)=1+x+x^2+...$");
  return 0;
}
/*________________________________________________________________*/
int oneminusxseries3(term t, term arg, term *next, char *reason)
/* 1/(1-x) = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = oneminusxseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"$1/(1-x)=1+x+...x^n_...$");
  return 0;
}

/*________________________________________________________________*/
int oneplusxseries(term t, term arg, term *next, char *reason)
{ int flag=0;
  term a,temp,denom;
  short savenextassumption = get_nextassumption();
  int err;
  term n;
  if(!FRACTION(t))
     return 1;
  denom = ARG(1,t);
  if(FUNCTOR(denom) != '+' || ARITY(denom) != 2)
     return 1;
  if(ONE(ARG(1,denom)))
     temp = make_fraction(one,sum(var0,one));
  else
     temp = make_fraction(one,sum(one,var0));
  err = unify1(temp,t,&a,&flag);
  if(err)
      { RELEASE(ARG(1,temp));
        RELEASE(temp);
        return 1;
      }
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  err = check1(lessthan(abs1(a),one));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  err = infer(equation(a,zero));
  if(!err)
     { errbuf(0,english(2326));  /* The resulting series would converge only at isolated points */
       set_nextassumption(savenextassumption);
       return 1;
     }
  *next = sigma(product(make_power(minusone,n),make_power(a,n)),n,zero,infinity);
  HIGHLIGHT(*next);
  strcpy(reason,"$$1/(1+x) = sum((-1)^nx^n,n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int oneplusxseries2(term t, term arg, term *next, char *reason)
/* 1/(1+x) = ...  with 3 terms and ldots */
{ term temp;
  int err = oneplusxseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"$1/(1+x)=1-x+x^2+...$");
  return 0;
}
/*________________________________________________________________*/
int oneplusxseries3(term t, term arg, term *next, char *reason)
/* 1/(1+x) = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = oneplusxseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"$1/(1+x)=1-x+...x\\supn...$");
  return 0;
}
/*________________________________________________________________*/
int lnseries(term t, term arg, term *next, char *reason)
/* ln(1-x) = -(x+x^2/2+...+x^n/n...) */
{ int flag=0;
  term a,temp;
  int err;
  term n;
  short savenextassumption;
  temp = ln1(sum(one,tnegate(var0)));
  err = unify1(temp,t,&a,&flag);
  if(err)
     { RELEASE(ARG(0,temp));
       RELEASE(temp);
       return 1;
     }
  savenextassumption = get_nextassumption();
  err = check1(lessthan(abs1(a),one));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  err = infer(equation(a,zero));
  if(!err)
     { errbuf(0,english(2326));  /* The resulting series would converge only at isolated points */
       set_nextassumption(savenextassumption);
       return 1;
     }
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  *next = tnegate(sigma(make_fraction(make_power(a,n),n),n,one,infinity));
  strcpy(reason,"$$ln(1-x) = -sum(x^n/n,n,1,infinity)$$");
  HIGHLIGHT(*next);
  return 0;
}
/*________________________________________________________________*/
int lnseries2(term t, term arg, term *next, char *reason)
/* ln(1-x) = ...  with 3 terms and ldots */
{ term temp;
  int err = lnseries(t,arg,&temp,reason);
  if(err)
     return 1;
  assert(NEGATIVE(temp));
  temp = ARG(0,temp);
  *next = tnegate(series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three)));
  HIGHLIGHT(*next);
  strcpy(reason,"ln(1-x) =             -(x+x^2/2+x^3/3...)");
  return 0;
}
/*________________________________________________________________*/
int lnseries3(term t, term arg, term *next, char *reason)
/* 1/(1+x) = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = lnseries(t,arg,&temp,reason);
  if(err)
     return 1;
  assert(NEGATIVE(temp));
  temp = ARG(0,temp);
  *next = tnegate(series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two));
  strcpy(reason,"ln(1+x) =             -(x+x^2/2+...x^n/3...)");
  return 0;
}
/*________________________________________________________________*/
int lnseriesminus(term t, term arg, term *next, char *reason)
/* ln(1+x) = x-x^2/2+...+x^n/n... */
{ int flag=0;
  term a,temp;
  int err;
  term n;
  short savenextassumption;
  temp = ln1(sum(one,var0));
  err = unify1(temp,t,&a,&flag);
  if(err ||
     ( NEGATIVE(a) && get_mathmode() == AUTOMODE)    // if a is negative, we should use lnseries, rather than lnseriesminus, at least in automode
    )
     { RELEASE(ARG(0,temp));
       RELEASE(temp);
       return 1;
     }
  savenextassumption = get_nextassumption();
  err = check1(lessthan(abs1(a),one));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  err = infer(equation(a,zero));
  if(!err)
     { errbuf(0,english(2326));  /* The resulting series would converge only at isolated points */
       set_nextassumption(savenextassumption);
       return 1;
     }
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  *next = sigma(product(make_power(minusone,sum(n,one)),make_fraction(make_power(a,n),n)),n,one,infinity);
  strcpy(reason,"$$ln(1-x)= sum((-1)^n (x^(n+1)/n),n,1,infinity)$$");
  HIGHLIGHT(*next);
  return 0;
}
/*________________________________________________________________*/
int lnseriesminus2(term t, term arg, term *next, char *reason)
/* ln(1+x) = ...  with 3 terms and ldots */
{ term temp;
  int err = lnseriesminus(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"ln(1+x) =             x-x^2/2+x^3/3-...");
  return 0;
}
/*________________________________________________________________*/
int lnseriesminus3(term t, term arg, term *next, char *reason)
/* 1/(1+x) = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = lnseriesminus(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  strcpy(reason,"ln(1+x) =             x+x^2/2+...x^n/3...");
  return 0;
}

/*________________________________________________________________*/
int expseries(term t, term arg, term *next, char *reason)
/* e^x = 1+x+...x^n/n!... */
{ term a,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(!equals(ARG(0,t),eulere))
     return 1;
  a = ARG(1,t);
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  *next = sigma(make_fraction(make_power(a,n),factorial1(n)),n,zero,infinity);
  HIGHLIGHT(*next);
  strcpy(reason,"$$e^x = sum(x^n/n!,n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int expseries2(term t, term arg, term *next, char *reason)
/* 1/(1-x) = ...  with 3 terms and ldots */
{ term temp;
  int err = expseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"e^x = 1+x+x^2/2!+...");
  return 0;
}
/*________________________________________________________________*/
int expseries3(term t, term arg, term *next, char *reason)
/* 1/(1-x) = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = expseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"e^x = 1+x+...x^n/n!...");
  return 0;
}
/*________________________________________________________________*/
int negexpseries(term t, term arg, term *next, char *reason)
/* e^-x = 1-x+...x^/n!... */
{ term a,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(!equals(ARG(0,t),eulere))
     return 1;
  a = ARG(1,t);
  if(!NEGATIVE(a))
     return 1;
  a = ARG(0,a);
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  *next = sigma(make_fraction(product(make_power(minusone,n),make_power(a,n)),factorial1(n)),n,zero,infinity);
  HIGHLIGHT(*next);
  strcpy(reason,"$$e^x = sum((-1)^nx^n/n!,n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int negexpseries2(term t, term arg, term *next, char *reason)
/* e^-x = 1-x+...x^n/n!...  with 3 terms and ldots */
{ term temp;
  int err = negexpseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"e^-x = 1-x+x^2/2!+...");
  return 0;
}
/*________________________________________________________________*/
int negexpseries3(term t, term arg, term *next, char *reason)
/* e^-x = 1-x+...x^n/n!...  with 2 terms and ldots and general term */
{ term temp;
  int err = negexpseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"e^x = 1-x+...x^n/n!...");
  return 0;
}

/*________________________________________________________________*/
int sinseries(term t, term arg, term *next, char *reason)
/* expand sin x in a power series */
{ term a,twonplusone,n;
  if(FUNCTOR(t) != SIN)
     return 1;
  a = ARG(0,t);
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  twonplusone = sum(product(two,n),one);
  *next = sigma(product(make_fraction(make_power(minusone,n),factorial1(twonplusone)),
                        make_power(a,twonplusone)
                       ),
                n,zero,infinity
               );
  SETCOLOR(*next,YELLOW);
  strcpy(reason,"$$sin x = sum((-1)^n/(2n+1)! x^(2n+1),n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int sinseries2(term t, term arg, term *next, char *reason)
/* sin x = ...  with 3 terms and ldots */
{ term temp;
  int err = sinseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"sin x =              x-x^3/3!+x^5/5!+...");
  return 0;
}
/*________________________________________________________________*/
int sinseries3(term t, term arg, term *next, char *reason)
/* sin x = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = sinseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"sin x =              x-x^3/3!+(-1)^nx^n/n!+...");
  return 0;
}

/*________________________________________________________________*/
int cosseries(term t, term arg, term *next, char *reason)
/* expand cos x in a power series */
{ term a,twon,n;
  if(FUNCTOR(t) != COS)
     return 1;
  a = ARG(0,t);
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  twon = product(two,n);
  *next = sigma(product(make_fraction(make_power(minusone,n),factorial1(twon)),
                        make_power(a,twon)
                       ),
                n,zero,infinity
               );
  HIGHLIGHT(*next);
  strcpy(reason, "$$cos x = sum((-1)^n/(2n)! x^(2n),n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int cosseries2(term t, term arg, term *next, char *reason)
/* cos x = ...  with 3 terms and ldots */
{ term temp;
  int err = cosseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"cos x =              1-x^2/2+x^4/4!+...");
  return 0;
}
/*________________________________________________________________*/
int cosseries3(term t, term arg, term *next, char *reason)
/* cos x = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = cosseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"cos x =              1-x^2/2!+(-1)^nx^(2n)/(2n)!+...");
  return 0;
}

/*________________________________________________________________*/
int tanseries(term t, term arg, term *next, char *reason)
/* expand tan x in a power series,  where x is given by arg */
{ term x,twon,n,nminusone,c,denom;
  int err;
  short savenextassumption;
  if(FUNCTOR(t) != TAN)
     return 1;
  x = ARG(0,t);
  n = getindexvar(t,"knmjpqrs");
  nminusone = sum(n,minusone);
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  savenextassumption = get_nextassumption();
  err = check1(lessthan(abs1(x),piover2));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  twon = product(two,n);
  denom =  factorial1(twon);
  c = make_fraction(product3(make_power(two,twon),sum(make_power(two,product(two,n)),minusone),bernoulli(twon)), denom);
  *next = sigma(product3 (make_power(minusone,nminusone),c, make_power(x,sum(twon,minusone))),
                n,one,infinity
               );
  HIGHLIGHT(*next);
  strcpy(reason, "$$tan x = sum((-1)^(n-1) (2^(2n)(2^(2n)-1) bernoulli(2n))/(2n)! x^(2n-1),n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int tanseries2(term t, term arg, term *next, char *reason)
/* tan x = ...  with 3 terms and ldots */
{ term temp;
  int err = tanseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason, "$$tan x = sum((-1)^(n-1) (2^(2n)(2^(2n)-1) bernoulli(2n))/(2n)! x^(2n-1),n,0,infinity,-3)$$");
  return 0;
}
/*________________________________________________________________*/
int tanseries3(term t, term arg, term *next, char *reason)
/* tan x = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = tanseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
   strcpy(reason, "$$tan x = sum((-1)^(n-1) (2^(2n)(2^(2n)-1) bernoulli(2n))/(2n)! x^(2n-1),n,0,infinity,2)$$");
  return 0;
}

/*________________________________________________________________*/
int cotseries(term t, term arg, term *next, char *reason)
/* expand  x cot x in a power series,  where x is given by arg */
/* also works on x^p cot x and on cot x */
{ term x,twon,n,c,denom,p,temp;
  int err;
  short savenextassumption;
  if(FUNCTOR(t) != COT && !(FUNCTOR(t) == '*' && ARITY(t) == 2 && FUNCTOR(ARG(1,t)) == COT))
      return 1;
  if(FUNCTOR(t) == COT)
      { x = ARG(0,t);
        p = reciprocal(x);
      }
  else
      
      { x = ARG(0,ARG(1,t));
        temp = ARG(0,t);
        if(FUNCTOR(temp) == '^' && !(equals(ARG(0,temp),x)) && ISINTEGER(ARG(1,temp)))
            return 1;
        if(! equals(temp,x) && FUNCTOR(temp) != '^')
           return 1; 
        if(equals(temp,x))
            p = one;
        else
           { long j = INTDATA(ARG(1,temp))-1;
             if(j < 0) 
                 return 1;
              p = make_power(x,make_int(j));
           }
       }
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  savenextassumption = get_nextassumption();
  err = check1(lessthan(abs1(x),pi_term));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  twon = product(two,n);
  denom = factorial1(twon);
  c = make_fraction(product(make_power(two,twon), bernoulli(product(two,n))), denom);
  *next = product(p,sigma(product3 (make_power(minusone, n),c, make_power(x,twon)),
                n,zero,infinity)
               );
  HIGHLIGHT(*next);
  strcpy(reason, "$$x cot x = sum((-1)^n (2^(2n)  bernoulli(2n))/(2n)! x^(2n-1),n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int cotseries2(term t, term arg, term *next, char *reason)
/* x cot x = ...  with 3 terms and ldots */
{ term temp;
  int err = cotseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason, "$$x cot x = sum((-1)^n (2^(2n)  bernoulli(2n))/(2n)! x^(2n-1),n,0,infinity,-3)$$");
  return 0;
}
/*________________________________________________________________*/
int cotseries3(term t, term arg, term *next, char *reason)
/* x cot  = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = cotseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
   strcpy(reason, "$$x cot x = sum((-1)^n (2^(2n)  bernoulli(2n))/(2n)! x^(2n-1),n,0,infinity,2)$$");
  return 0;
}
/*________________________________________________________________*/
int secseries(term t, term arg, term *next, char *reason)
/* expand  sec x in a power series,  where x is given by arg */
/* also works on a/cos x  */
{ term x,twon,n,c,denom,temp;
  int err;
  short savenextassumption;
  if(FRACTION(t))
      { denom = ARG(1,t);
        if(FUNCTOR(denom) != COS)
            return 1;
        x = ARG(0,denom);
        if(!ispolyin(ARG(0,t),x))
            return 1;
        err = secseries(sec1(x),arg,&temp,reason);
        if(err) 
           return 1;
        *next = product(ARG(0,t),temp);
        return 0;
      }
  if(FUNCTOR(t) != SEC) 
      return 1;
  x = ARG(0,t);
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  savenextassumption = get_nextassumption();
  err = check1(lessthan(abs1(x),piover2));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  twon = product(two,n);
  denom = factorial1(twon);
  c =    make_fraction( eulernumber(twon), denom);
  *next = sigma(product3 (make_power(minusone, n),c, make_power(x,twon)),
                n,zero,infinity
               );
  HIGHLIGHT(*next);
  strcpy(reason, "$$sec x = sum((-1)^n  eulernumber(2n)/(2n)! x^(2n),n,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int secseries2(term t, term arg, term *next, char *reason)
/* x cot x = ...  with 3 terms and ldots */
{ term temp;
  int err = secseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
   strcpy(reason, "$$sec x = sum((-1)^n  eulernumber(2n)/(2n)! x^(2n),n,0,infinity,-3)$$");
  return 0;
}
/*________________________________________________________________*/
int secseries3(term t, term arg, term *next, char *reason)
/* sec x  = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = secseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason, "$$sec x = sum((-1)^n  eulernumber(2n)/(2n)! x^(2n),n,0,infinity,2)$$");
  return 0;
}
/*________________________________________________________________*/
int bernoulliseries(term t, term arg, term *next, char *reason)
/* expand x/(e^x-1) in a power series,  where x is given by arg */
{ term x,twon,n,c,denom, temp;
  if(!FRACTION(t))
      return 1;
  if(FUNCTOR(ARG(1,t)) != '+' || ARITY(ARG(1,t)) != 2)
      return 1;
  if(!equals(ARG(1,ARG(1,t)),minusone))
      return 1;
  temp = ARG(0,ARG(1,t));
  if(FUNCTOR(temp) != '^' || !equals(ARG(0,temp),eulere))
     return 1;
  x = ARG(0,t);
  if(!equals(ARG(0,temp),eulere))
     return 1;
  if(!equals(ARG(1,temp),x))
     return 1;
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  twon = product(two,n);
  denom = factorial1(product(two,n));
  c = make_fraction(bernoulli(twon),denom);
  *next = make_term('+',3);
  ARGREP(*next,0,one);
  ARGREP(*next,1,tnegate(make_fraction(x,two)));
  ARGREP(*next,2,sigma(product(c,make_power(x,product(two,n))),n,one,infinity));
  HIGHLIGHT(*next);
  strcpy(reason, "$$x/(e^x-1) = 1-x/2 + sum(( bernoulli(2n)/((2n)!)) x^(2n),n,1,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int bernoulliseries2(term t, term arg, term *next, char *reason)
/* tan x = ...  with 3 terms and ldots */
{ term temp;
  int err = bernoulliseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"x/(e^x-1) =          1- x/2 + x^2/2+x^4/4!+...");  // FINISH THIS
  return 0;
}
/*________________________________________________________________*/
int bernoulliseries3(term t, term arg, term *next, char *reason)
/* tan x = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = bernoulliseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"tan x = 1-x^2/2!+    (-1)^(n-1) (2^(2n)(2^(2n)-1)B_(2n)x^(2n)/(2n)!+..."); // FINISH THIS
  return 0;
}
/*________________________________________________________________*/
int atanseries(term t, term arg, term *next, char *reason)
/* atan x = x - x^3/3 + x^5/5... */
{ term a,twonplusone,n;
  int err;
  short savenextassumption;
  if(FUNCTOR(t) != ATAN)
     return 1;
  a = ARG(0,t);
  savenextassumption = get_nextassumption();
  err = check1(lessthan(abs1(a),one));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
       return 1;
     }
  err = infer(equation(a,zero));
  if(!err)
     { errbuf(0,english(2326));  /* The resulting series would converge only at isolated points */
       set_nextassumption(savenextassumption);
       return 1;
     }
  n = getindexvar(t,"knmjpqrs");
  if(FUNCTOR(n) == ILLEGAL)
     { errbuf(0, english(1448));
       /* Too many subscripted variables, can't make more. */
       return 1;
     }
  twonplusone = sum(product(two,n),one);
  *next = sigma(product(make_power(minusone,n),
                        make_fraction(make_power(a,twonplusone),twonplusone)
                       ),
                n,zero,infinity
               );
  HIGHLIGHT(*next);
  strcpy(reason,"$$arctan x = sum((-1)^k (x^(2k+1)/(2k+1)),k,0,infinity)$$");
  return 0;
}
/*________________________________________________________________*/
int atanseries2(term t, term arg, term *next, char *reason)
/* atan x = ...  with 3 terms and ldots */
{ term temp;
  int err = atanseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
  strcpy(reason,"atan x =              x-x^3/3+x^5/5+...");
  return 0;
}
/*________________________________________________________________*/
int atanseries3(term t, term arg, term *next, char *reason)
/* atan x = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = atanseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"atan x = x-x^3/3+...  +x^(2n+1)/(2n+1)+...");
  return 0;
}

/*________________________________________________________________________*/
int zetaseries(term t, term arg, term *next, char *reason)
/* power series for the Riemann zeta function */
{ term s,n;
  int err;
  int savenextassumption = get_nextassumption();
  if(FUNCTOR(t) != RIEMANNZETA)
     return 1;
  s = ARG(0,t);
  err = check1(lessthan(one,s));
  if(err)
     { errbuf(0,english(2325)); /* The resulting series would not be convergent */
       set_nextassumption(savenextassumption);
     }
  n = getnewboundintvar(t,"nkmjNKMj");
  *next = indexedsum(make_fraction(one,make_power(n,s)),n,one,infinity);
  HIGHLIGHT(*next);
  SETCONVERGENT(*next);
  strcpy(reason, "$$ zeta(s) = sum(1/n^s,n,1,infinity)$$");
  return 0;
}
  
/*________________________________________________________________*/
int zetaseries2(term t, term arg, term *next, char *reason)
/* zeta x = ...  with 3 terms and ldots */
{ term temp;
  int err = zetaseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),tnegate(three));
  HIGHLIGHT(*next);
 strcpy(reason,"\\zeta(s) =            1 + 1/2^s + 1/3^x +...+1/n^2");  
  return 0;
}
/*________________________________________________________________*/
int zetaseries3(term t, term arg, term *next, char *reason)
/* zeta x = ...  with 2 terms and ldots and general term */
{ term temp;
  int err = zetaseries(t,arg,&temp,reason);
  if(err)
     return 1;
  *next = series(ARG(0,temp),ARG(1,temp),ARG(2,temp),ARG(3,temp),two);
  HIGHLIGHT(*next);
  strcpy(reason,"\\zeta(s) =           1 + 1/2^s + 1/3^x +...+1/n^2");  
  return 0;
}


/*________________________________________________________________*/
int difseries(term t, term arg, term *next, char *reason)
/* Push d/dx into sigma for a power series */

{ term u,n,lo,hi,s,x,a;
  if(FUNCTOR(t) != DIFF)
     return 1;
  x = ARG(1,t);
  s = ARG(0,t);
  if(!is_power_series(s,x,&a))
     return 1;
  u = ARG(0,s);
  n = ARG(1,s);
  lo = ARG(2,s);
  hi = ARG(3,s);
  *next = ARITY(s) == 4  ? sigma(diff(u,arg),n,lo,hi) : series(diff(u,arg),n,lo,hi,ARG(4,s));
  strcpy(reason,"$d/dx( u) = \\sigma du/dx$");
  if(equals(hi,infinity))
     strcat(reason,english(2170));    /*      for power series */
  HIGHLIGHT(ARG(0,*next));
  return 0;
}


/*________________________________________________________________*/
int intseries(term t, term arg, term *next, char *reason)
/* Integrate a power series term by term */
{ term u,n,s,x,lo,a,w,c,b,newpower;
  if(FUNCTOR(t) != INTEGRAL)
     return 1;
  s = ARG(0,t);
  x = ARG(1,t);
  if(!is_power_series(s,x,&a))
     return 1;
  if(FUNCTOR(s) != SUM)
     assert(0);  // since is_power_series succeeded 
  u = ARG(0,s);
  n = ARG(1,s);
  lo = ARG(2,s);
  twoparts(u,x,&c,&b);
  if(FUNCTOR(b)!='^')
     return 1;  /* assert(0), since is_power_series succeeded */
  polyval(sum(ARG(1,b),one),&newpower);
      /* make w the evaluated indefinite integral of u */
  polyval(make_fraction(product(c,make_power(ARG(0,b),newpower)),newpower),&w);
  if(ARITY(t) == 2)
     { /* an indefinite integral */
       *next = ARITY(s) == 4 ? sigma(w,n,lo,infinity) : series(w,n,lo,infinity,ARG(4,s));
       /* Mathpert's general machinery will insert a constant of integration */
     }
  else
     { /* a definite integral */
       *next = ARITY(s) == 4 ? sigma(evalat(w,x,ARG(2,t),ARG(3,t)),n,lo,infinity):
                               series(evalat(w,x,ARG(2,t),ARG(3,t)),n,lo,infinity,ARG(4,s));
     }
  strcpy(reason, english(2327));    /* integrate power series term by term */
  SETCOLOR(ARG(0,*next),YELLOW);
  return 0;
}
/*________________________________________________________________*/
int reversedifseries(term t, term arg, term *next, char *reason)
/* pull d/dx out of a series. */

{ term u,n,lo,hi,w;
  if(FUNCTOR(t) != SUM)
     return 1;
  u = ARG(0,t);
  n = ARG(1,t);
  lo = ARG(2,t);
  hi = ARG(3,t);
  if(FUNCTOR(u) != DIFF)
      return 1;
  w = ARITY(t) == 4 ? sigma(ARG(0,u),n,lo,hi) : series(ARG(0,u),n,lo,hi,ARG(4,t));
  *next = diff(w,ARG(1,u));
  strcpy(reason,"$\\sigma du/dx = d/dx \\sigma u$");
  if(equals(hi,infinity))
     strcat(reason,english(2170));    /*      for power series */
  HIGHLIGHT(ARG(0,*next));
  return 0;
}
/*________________________________________________________________*/
int reverseintseries(term t, term arg, term *next, char *reason)
{ term u,n,lo,hi,w;
  if(FUNCTOR(t) != SUM)
     return 1;
  u = ARG(0,t);
  n = ARG(1,t);
  lo = ARG(2,t);
  hi = ARG(3,t);
  if(FUNCTOR(u) != INTEGRAL)
     return 1;
  w = ARITY(t) == 4 ? sigma(ARG(0,u),n,lo,hi) : series(ARG(0,u),n,lo,hi,ARG(4,t));
  if(ARITY(u) == 2)
     *next = integral(w,ARG(1,u));
  else
     *next = definite_integral(w,ARG(1,u),ARG(2,u),ARG(3,u));
  strcpy(reason,"$\\int(\\sum u) dx  = \\sum \\int u dx$");
  if(equals(hi,infinity))
     strcat(reason,english(2170));  /*      for power series */
  SETCOLOR(ARG(0,*next),YELLOW);
  return 0;
}


/*________________________________________________________________________*/
static int first_terms_aux(term t, term *arg)
/* t is a SUM; return in *arg a term that is an integer,
 the number of initial terms for which the exponent of the eigenvariable is negative.
 Return 0 for success, 1 for failure.
*/
{ term u,k,x,v,c,m,lo;
  double oldval, loval,exp;
  term *vars = get_varlist();
  int nvars = get_nvariables();
  int err, ct, i;
  if(FUNCTOR(t) != SUM)
      return 1;
  u = ARG(0,t);
  k = ARG(1,t);
  lo = ARG(2,t);
  if(!numerical(lo) || !ISATOM(k))
      return 1;
  /* Now we need to get the power series variable x.
     When this is called, the index variable k is the eigenvariable,  set by autosimp,
     so we need to recover the power series variable directly from u. */
  nvars = variablesin(u,&vars);
  for(i=0; i<nvars; i++)
     { if(equals(vars[i],k)) continue;
       x = vars[i];
       twoparts(u,x,&c,&v);
       if(FUNCTOR(v) == '^' && equals(ARG(0,v),x))
           { m = ARG(1,v);
             break;
           }
     }
  if(i==nvars)
     return 1;
  oldval = VALUE(k);
  deval(lo,&loval);
  SETVALUE(k,loval);
  err = deval(m,&exp);
  SETVALUE(k,oldval);
  if(err)
      return 1;
  if(exp >=  -0.001)
      return 1;
  for(ct = 1; ct <= 10; ct++)
     { SETVALUE(k,loval + ct);
       err = deval(m,&exp);
       if(err || exp >= -0.001)
           break;
     }
  SETVALUE(k,oldval);
  *arg = make_int(ct);
  return 0;
}

/*________________________________________________________________________*/
int seriesfirstterms(term t, term arg, term *next, char *reason)
/* split off the first few terms (how many is given by arg) of an infinite series. */
/* The number of terms is limited to 1000 */

{ long nn;
  unsigned short n;
  term l,newlo,temp,index,q,last,u;
  int saveflag;
  int i;
  aflag flag1, flag2;
  if(FUNCTOR(arg) == ILLEGAL)
      { // we're in auto mode and need to supply the arg.  
        int err = first_terms_aux(t,&arg);
        if(err)
           return 1;
      }
  if(!ISINTEGER(arg))
     return 1;
  nn =  INTDATA(arg);
  if(nn > 1000)
     { errbuf(0, english(828));
          /* You can't show more than 1000 terms */
       return 1;
     }
  flag1 = flag2 = get_arithflag();
  flag1.intexp = flag1.ratexp = flag1.negexp = flag1.fract = flag1.gcd = 0;
  set_arithflag(flag1);
  n = (unsigned short) nn;
  if(FUNCTOR(t) != SUM)
     return 1;
  if(!equals(ARG(3,t),infinity))
     return 1;
  q = ARG(0,t);  /* summand */
  l = ARG(2,t);  /* lower limit of sum */
  index = ARG(1,t);  /* index variable */
  saveflag = get_polyvalzeropowerflag();
  set_polyvalzeropowerflag(1);
  if(ZERO(l))
     newlo = arg;
  else
     { temp = sum(l,arg);
       polyval(temp,&newlo);
     }
  *next = make_term('+',(unsigned short)(n+1));
  for(i=0;i<n;i++)
     { polyval(sum(make_int(i),l),&temp);
       subst(temp,index,q,&u);
       polyval(u,ARGPTR(*next) + i);
       HIGHLIGHT(ARG(i,*next));
     }
  set_polyvalzeropowerflag(saveflag);
  set_arithflag(flag2);
  copy(t,&last);
  ARGREP(last,2,newlo);
  HIGHLIGHT(ARG(2,last));
  ARGREP(*next,n,last);
  strcpy(reason, english(831));  /* split off first terms */
  return 0;
}
/*________________________________________________________________________*/
int seriesmoreterms(term t, term arg, term *next, char *reason)
/* lower the first limit of an infinite series, subtracting off the
corresponding terms.  Example:  sum(x^n,n,2,infinity) becomes
sum(x^n,n,0,infinity) - (1+x)  */
/* The number of terms is limited to 1000 */
/* The prompt is, Decrease the lower limit by how much?  */

{ long nn;
  unsigned short n;
  term l,newlo,temp,index,q,p,newseries;
  int i;
  int problemtype = get_problemtype();
  if(problemtype == ADDSERIES && FUNCTOR(arg) == ILLEGAL && FUNCTOR(t) == SUM)
     { term u = ARG(0,t);
       term n = ARG(1,t);
       term lo = ARG(2,t);
       unsigned f = FUNCTOR(u);
       if(f != '^' && f != '/')
          return 1;   // don't use it on a telescoping series for example
       if(!ISINTEGER(lo) || INTDATA(lo) < 1)  // 1 is OK
         return 1;
       subst(lo,n,u,&temp);
       if(check1(defined(temp)))  // check1 returns 0 for success
           {
             return 1;  // u[n:=lo]  is undefined
           }
       arg = lo;
    }
  if(FUNCTOR(t) == '+' && FUNCTOR(arg) == ILLEGAL && problemtype == POWERSERIES)
     { /* it can be called on a sum of series in auto mode.  Then we have to 
          make the lower limits match, provided the exponents already match and the index variables already match */
       int n = ARITY(t);
       int i,err;
       term u,c,v,w,p,q,r,ans,k,exp,savek,lo;
       double z;
       unsigned short path[10];
       term x = get_eigenvariable();
       int flag = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            twoparts(u,x,&c,&v);
            if(FUNCTOR(v) != SUM) 
                continue;
            w = ARG(0,v);  // the summand
            k = ARG(1,v);  // the index variable
            twoparts(w,x,&c,&p);  // the constant and the power term
            if(FUNCTOR(p) != '^' || !equals(ARG(0,p),x))
                return 1;
            if(!flag)
                { ++flag;      // first series in the sum
                  exp = ARG(1,p);
                 // savei = i;   // which series in the original sum of series
                 // we don't need savei,  we only use lo.  The action will
                 // take place at the second sum.
                  savek = k;   // index variable
                  lo = ARG(2,v);  // lower limit of sum
                  continue;
                }
            if(!equals(k,savek))
                return 1;  // index variables don't match
            if(!equals(ARG(1,p),exp))
                return 1;  // exponents don't match
            if(!equals(ARG(2,v),lo))  // lower limits of sums don't match 
                {  int whichsum = 1;
                   q = ARG(2,v);
                   polyval(sum(q,tnegate(lo)),&r);
                   if(FUNCTOR(r) == '-')
                       { r = ARG(0,r);
                         whichsum = 0;
                       }
                   if(!INTEGERP(r))
                       return 1;
                   deval(r,&z);
                   if(z > 100)
                       return 1;  // otherwise the screen will be a mess
                   if(whichsum == 1)
                      { err = seriesmoreterms(v,r,&ans,reason);
                        if(err)
                            return 1;
                      }
                   else
                      { err = seriesfirstterms(v,r,&ans,reason);
                        if(err)
                            return 1;
                      }
                   subst(ans,v,t,next);
                   path[0] = '+';
                   path[1] = i+1;
                   if(FUNCTOR(u) == SUM)
                      { path[2] = 0;
                        set_pathtail(path);
                        if(whichsum==0)
                            SetShowStepOperation(seriesfirstterms);
                        return 0;
                      }
                   if(NEGATIVE(u))
                      { path[2] = '-';
                        path[3] = 1;
                        if(FUNCTOR(ARG(0,u)) == SUM)
                           { path[4] = 0;
                              set_pathtail(path);
                              if(whichsum==0)
                                 SetShowStepOperation(seriesfirstterms);
                              return 0;
                           }
                       }
                  }                                  
            }  // close for loop
            return 1;
      }

  if(FUNCTOR(t) != SUM)
     return 1;
  if(!ISINTEGER(arg) || ZERO(arg))
     return 1;
  nn =  INTDATA(arg);
  if(nn > 1000)
     { errbuf(0, english(2245));
          /* You can't insert more than 1000 terms */
       return 1;
     }
  n = (unsigned short) nn;

  if(!equals(ARG(3,t),infinity))
     return 1;
  if(equals(ARG(2,t),minusinfinity))
     return 1;
  q = ARG(0,t);  /* summand */
  l = ARG(2,t);  /* lower limit of sum */
  index = ARG(1,t);  /* index variable */
  if(ZERO(l))
     newlo = tnegate(arg);
  else if(equals(arg,l))
     newlo = zero;
  else
     { temp = sum(l,tnegate(arg));
       polyval(temp,&newlo);
     }
  p = make_term('+',n);
  for(i=0;i<n;i++)
    { polyval(sum(make_int(i),newlo),&temp);
      subst(temp,index,q,ARGPTR(p) + i);
      if(check1(defined(ARG(i,p))))
         return 1;  // one of the terms we would want to add is not defined
    }
  HIGHLIGHT(p);
  copy(t,&newseries);
  ARGREP(newseries,2,newlo);
  HIGHLIGHT(ARG(2,newseries));
  *next = sum(newseries,tnegate(p));
  strcpy(reason, english(2252));  /* decrease lower limit */
  return 0;
}
/*________________________________________________________________________*/
int seriessubindex(term t, term arg, term *next, char *reason)
/* arg is in response to, Subtract ? from the index variable? */
{ term k;  /* the index variable */
  term hi,lo;  /* the limits */
  term u;    /* the summand */
  term newlo, v,kk;
  long A,B;
  if(FUNCTOR(t) == '+' && FUNCTOR(arg) == ILLEGAL && get_problemtype() == POWERSERIES)
     { /* it can be called on a sum of series in auto mode.  Then we have to 
          make the powers in the summands match, provided the index variables match already */
       int n = ARITY(t);
       int i,err;
       term c,v,w,p,q,r,ans,b,exp,savek;
       unsigned short path[10];
       term x = get_eigenvariable();
       int savei;
       int flag = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            twoparts(u,x,&c,&v);
            if(FUNCTOR(v) != SUM) 
                continue;
            w = ARG(0,v);
            k = ARG(1,v);
            twoparts(w,x,&c,&p);
            if(FUNCTOR(p) != '^' || !equals(ARG(0,p),x))
                return 1;
            if(!flag)
                { ++flag;
                  savek = k;
                  exp = ARG(1,p);
                  b = v;
                  savei = i;
                  continue;
                }
            if(!equals(k,savek))
                return 1;  // index variables don't match
            if(!equals(ARG(1,p),exp))
                {  q = ARG(1,p);
                   if(FUNCTOR(q)== '+')
                      { // then subtract from the index variable in this term
                        term c2,v2,w3;
                        polyval(sum(q,tnegate(exp)),&r);
                        if(!isinteger(r))
                            return 1;
                        twoparts(exp,k,&c2,&v2);
                        if(!ISINTEGER(c2) || !equals(v2,k))
                            return 1;
                        A = INTDATA(c2);
                        if(ISINTEGER(r))
                           B = INTDATA(r);
                        else if (NEGATIVE(r) && ISINTEGER(ARG(0,r)))
                           B = -INTDATA(r);
                        else
                           return 1;
                        if(B % A != 0)
                           return 1;
                        w3 = B > 0 ?  make_int(B/A) : tnegate(make_int(B/A));
                        err = seriessubindex(v,w3,&ans,reason);
                        if(err) return 1;
                        subst(ans,v,t,next);
                        path[0] = '+';
                        path[1] = i+1;
                        if(FUNCTOR(u) == SUM)
                           { path[2] = 0;
                             set_pathtail(path);
                             return 0;
                           }
                        if(NEGATIVE(u))
                           { path[2] = '-';
                             path[3] = 1;
                             if(FUNCTOR(ARG(0,u)) == SUM)
                                 { path[4] = 0;
                                   set_pathtail(path);
                                   return 0;
                                 }
                           }
                      }
                   else
                      { polyval(sum(exp,tnegate(q)),&r);
                        err = seriessubindex(b,r,&ans,reason);
                        if(err) return 1;
                        subst(ans,b,t,next);
                        u = ARG(savei,t);
                        path[0] = '+';
                        path[1] = savei +1;
                        if(FUNCTOR(u) == SUM)
                           { path[2] = 0;
                             set_pathtail(path);
                             return 0;
                           }
                        if(NEGATIVE(u))
                           { path[2] = '-';
                             path[3] = 1;
                             if(FUNCTOR(ARG(0,u)) == SUM)
                                 { path[4] = 0;
                                   set_pathtail(path);
                                   return 0;
                                 }
                           }
                      }
               }
            }  // close for loop
            return 1;
      }
  if(FUNCTOR(t) != SUM || ARITY(t) != 4)
      return 1;
  u = ARG(0,t);
  k = ARG(1,t);
  lo = ARG(2,t);
  hi = ARG(3,t);
  if(FUNCTOR(arg) == ILLEGAL)
      {  // called in case the exponent is k+3 for example
         term *atomlist;
         int nvars = variablesin(u,&atomlist);
         int i;
         term c,w,x,p,q;
         for(i=0;i<nvars;i++)
            { x = atomlist[i];
              if(equals(x,k)) continue;
               twoparts(u,x,&c,&v);
               if(FUNCTOR(v) != '^' || !equals(ARG(0,v),x))
                  continue;
               w  = ARG(1,v);
               if(FUNCTOR(w) != '+' || ARITY(w) != 2)
                  continue;
               if(equals(ARG(0,w),k))
                  { arg = ARG(1,w);
                    break;
                  }
               p = ARG(0,w);
               if(FUNCTOR(p) == '*' && ISINTEGER(ARG(0,p)) && equals(ARG(1,p),k) && isinteger(ARG(1,w)))
                   { q = ARG(1,w);
                     if(equals(q,ARG(0,p)))
                        { arg = one;
                          break;
                        }
                     if(NEGATIVE(q) && equals(ARG(0,q),ARG(0,p)))
                        { arg = minusone;
                          break;
                        }
                     A = INTDATA(ARG(0,p));
                     if(ISINTEGER(q))
                        B = INTDATA(q);
                     else if(NEGATIVE(q) && ISINTEGER(ARG(0,q)))
                        B = -INTDATA(ARG(0,q));
                     else 
                        return 1;  // maybe q was a bignum or a polynomial in k
                     if (B % A != 0)
                        return 1;
                     if(B == 0) return 1;
                     arg = B > 0 ? make_int(B/A) : tnegate(make_int(B/A));
                     break;
                   }
            }
         if(i==nvars)
            return 1;
       }   
  if(!equals(hi,infinity))
     return 1;
  if(contains(arg,FUNCTOR(k)))
     { errbuf(0, english(2239));
       /* expression to shift by cannot depend on the index variable */
       return 1;
     }
  if(equals(lo,minusinfinity))
     newlo = minusinfinity;
  else
     polyval(sum(lo,arg),&newlo);
  polyval(sum(k,tnegate(arg)),&kk);
  HIGHLIGHT(kk);
  subst(kk,k,u,&v);
  *next = make_term(SUM,4);
  ARGREP(*next,0,v);
  ARGREP(*next,1,k);
  HIGHLIGHT(newlo);
  ARGREP(*next,2,newlo);
  ARGREP(*next,3,infinity);
  strcpy(reason, english(2247));  /* subtract from index variable */
  return 0;
}
/*________________________________________________________________________*/
int seriesaddindex(term t, term arg, term *next, char *reason)
/* arg is in response to, Add ? to the index variable? */
{ int err;
  if(FUNCTOR(arg) == ILLEGAL)
      err  = seriessubindex(t,arg,next,reason);  // don't pass tnegate(illegal)
  else
      err  = seriessubindex(t,tnegate(arg),next,reason);
  if(err)
     return 1;
  strcpy(reason,english(2246));  /* add to index variable */
  return 0;
}
/*________________________________________________________________________*/
int seriesintdif(term t, term arg, term *next, char *reason)
/*  */
{ term x = get_eigenvariable();
  term p = history( get_currentline());
  term c,s;
  if(!contains(t,FUNCTOR(x)))
     return 1;
  if(FUNCTOR(p) == '*')
     { twoparts(p,x,&c,&s);
       if(!equals(t,s))
          return 1;
     }
   else if(!equals(t,p))
     return 1;
 
  *next = integral(diff(t,x),x);
  HIGHLIGHT(*next);
  strcpy(reason,"$$u = integral(diff(u,x),x)$$");
  return 0;
}

/*________________________________________________________________________*/
int seriesintdifdef(term t, term arg, term *next, char *reason)
/* $$u = integral(diff(u,t),t,0,x) + u0$$ */
{ term x,v,t0,tofv,p,c,s;
  x = get_eigenvariable();
  if(!contains(t,FUNCTOR(x)))
     return 1;
  p = history(get_currentline());
  if(!contains(t,FUNCTOR(x)))
     return 1;
  if(FUNCTOR(p) == '*')
     { twoparts(p,x,&c,&s);
       if(!equals(t,s))
          return 1;
     }
   else if(!equals(t,p))
     return 1;
  v = getnewvar(t,"tuvwz");
  psubst(zero,x,t,&t0);
  subst(v,x,t,&tofv);
  *next = sum(definite_integral(diff(tofv,v),v,zero,x),t0);
  HIGHLIGHT(*next);
  strcpy(reason,"$$u = integral(diff(u,t),t,0,x) + u0$$");
  return 0;
}
/*________________________________________________________________________*/
int seriesdifint(term t, term arg, term *next, char *reason)
/* $$u = diff(integral(u,x),x)$$ */
{ term x;
  if(!equals(t,history(get_currentline())))
     return 1;
  x = get_eigenvariable();
  if(!equals(t,history(get_currentline())))
     return 1;
  if(!contains(t,FUNCTOR(x)))
     return 1;
  *next = diff(integral(t,x),x);
  HIGHLIGHT(*next);
  strcpy(reason,"$$u = diff(integral(u,x),x)$$");
  return 0;
}
/*________________________________________________________________________*/
static int get_origin(term t, term x, term *a)
/*  if t contains a power series in (x-a) return a in *a;
    if t contains a power series in x return zero in *a.
    Return 0 for success.
*/
{ unsigned short i,n;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) == SUM && equals(ARG(3,t),infinity))
     { if(is_power_series(t,x,a))
          return 0;
       return 1;
     }
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(get_origin(ARG(i,t),x,a) == 0)
          return 0;
     }
  return 1;
}
/*________________________________________________________________________*/
static int get_cofi(term t, term *ans)
/* return a subterm of t with functor CONSTANTOFINTEGRATION in *ans,
if one exists, returning 0 for success.
*/
{ unsigned short i,n;
  if(FUNCTOR(t) == CONSTANTOFINTEGRATION)
     { *ans = t;
       return 0;
     }
  if(ATOMIC(t))
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(get_cofi(ARG(i,t),ans) == 0)
          return 0;
     }
  return 1;
}
/*________________________________________________________________________*/
int eliminatecofi(term t, term arg, term *next, char *reason)
/* Solve for constant of integration */
/* example, once we have reduced arctan x to
x-x^3/3 + ... + C
we change C to arctan(0)  with this operation
*/
{ term orig,x,a,u,v,w,r,q,ans;
  int err;
  int saveflag;
  if(!equals(t,history(get_currentline())))
     return 1;
  x = get_eigenvariable();
  if(contains(t,INTEGRAL))
     return 1;
  orig = history(0);
  /* check if t contains a power series in x or (x-a) */
  err = get_origin(t,x,&a);
  if(err)
     return 1;
  subst(a,x,t,&u);  /* example, t = x-x^2/2 +x^3/3 + ... + c1, a = 0 */
  saveflag = get_polyvalzeropowerflag();
  set_polyvalzeropowerflag(1);
  polyval(u,&v);    /* In the example v comes out 0 since polyval can simplify
                       a series with general term 0 to 0 */
  subst(a,x,orig,&w);  /* in the example, orig is ln(1+x) so w comes out ln 1 */
  polyval(w,&q);
  err = check1(defined(q));
  if(err)
     { /* example, ln(sin(x)/x).   Function is undefined at 0.  We must take the limit */
       limval(limit(arrow(x,a),orig),&w);
       polyval(w,&q);
       err = check1(defined(q));
       if(err)
           return 1;
     } 
  set_polyvalzeropowerflag(saveflag);
  if(FUNCTOR(arg) != CONSTANTOFINTEGRATION)
     { err = get_cofi(t,&arg);
       if(err)
          return 1;
     }
  subst(x,arg,equation(v,q),&r);    /* r comes out 0 + x = ln 1  */
  err = ssolve(r,x,&ans);           /* x = ln 1  */
  if(err || FUNCTOR(ans) != '=')
     return 1;
 
  HIGHLIGHT(ARG(1,ans));
  subst(ARG(1,ans),arg,t,next);
  strcpy(reason, english(2324));  /* solve for constant of integration */
  return 0;
}

/*____________________________________________________________________________________*/
int is_power_series(term t, term x, term *a)
/* return 1 if t is a power series in x about x=a.  Return a in *a. */
{ term c,s,base,u,c2,s2;
  if(FUNCTOR(t) != SUM)
     return 0;
  if(!equals(ARG(3,t),infinity))
     return 0;
  u = ARG(0,t);
  twoparts(u,x,&c,&s);
  if(FUNCTOR(s) != '^')
     { if(FUNCTOR(s) == '/' || FUNCTOR(s) == '*')
       twoparts(s,x,&c2,&s2);
       if(FUNCTOR(s2)!= '^')
          return 0;
       polyval(product(c,c2),&c);
       s = s2;
     }
  if(equals(ARG(0,s),x))
     { *a = zero;
       return 1;
     }
  base = ARG(0,s);
  if(FUNCTOR(base) != '+')
     return 0;
  polyval(sum(x,tnegate(base)),a);
  return contains(*a,FUNCTOR(x)) ? 0 : 1;
}
/*____________________________________________________________*/
int get_new_fname(unsigned short *f, char *buffer)
/* return a new function name suitable for use as coefficients in a
power series defined by series division;  in this case Mathpert has
to make a (recursive) function definition internally.  Return 0 for
success or 1 if there is no room for more function definitions, or
(very unlikely) all the candidate letters in the 'letters' array below
are used up.
*/

{ int i,j;
  char *letters = "cabdpqrsuvwzCABPQRSUVWZ";
  int nletters = (int) strlen(letters);
  char c;
  char *name;
  term *varlist = get_varlist();
  int nvars = get_nvariables();
  int nextfunction = nuserfunctions();
  if(nextfunction == MAXUSERFUNCTIONS)
     return 1;
  /* pick the first member of 'letters' that is not in varlist or
     already used for a function definition. */
  for(i=0;i<nletters;i++)
     { c = letters[i];
       for(j=0;j<nvars;j++)
          { if(FUNCTOR(varlist[j])==c)
               break;
          }
       if(j<nvars)
          continue;
       for(j=0;j< (int)nextfunction;j++)
          { name = get_defnstring(j);
            if(c == name[0] && name[1] == '(')
               break;
          }
       if(j == (int)nextfunction)
          break;
     }
  if(i==nletters)
     return 1;
  *f = (unsigned short) c;
  buffer[0] = c;
  buffer[1] = '\0';
  return 0;
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists