Sindbad~EG File Manager

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

/* auto mode for differentiation, limits, and integration */
/*
M. Beeson
Original date 9.10.91
Last modified 2.27.99
6.14.00 modified stop_lhopital
3.9.01  added contains_trigsquare and code that uses it, to integrate x cos^2 x
3.10.01 last modified for version 1.624  
6.14.04 last modified
1.28.06 changed conditions for difpoly
4.12.06 added limabs to autolimit
5.6.13  include stdef.h
5.9.13 modified autoint to not evaluate integrals in POWERSERIES except inside the series; 
        but intseries (term by term integration) is used.
        changed limitflag to get_limitflag()
5.29.13  modified autocalc not to differentiate ln(a/b) or ln(ab) directly. 
5.30.13  modified use_logdif, but only for topic _logarithmic_differentiation.
6.10.13  added intsub at line 1286 to deal with integral(x e^(-x^2),x)  
9.26.14 removed unused function contains_half_power.
10.22.23 and its prototype
5.8.24  corrected 't' to 'u'  in the DIFF case of autodif
2.16.25  commented out unused 'logflag' in autolimit
*/

#include <assert.h>
#include <string.h>
#include <stddef.h> 
#include "globals.h"
#include "graphstr.h"
#include "display.h" /* coord */
#include "mpdoc.h"
#include "tdefn.h"
#include "checkarg.h" /* operator typedef            */
#include "ops.h"
#include "calc.h"     /* prototypes of operators     */
#include "probtype.h"
#include "prover.h"   /* for NOTDEFINED              */
#include "polynoms.h"
#include "match.h"
#include "cancel.h"
#include "factor.h"
#include "automode.h"
#include "integral.h" /* islinear                    */
#include "mplimits.h"   /* LIMITAND                    */
#include "order.h"    /* constant                    */
#include "symbols.h"
#include "trigpoly.h" /* algpoly                     */
#include "trig.h"     /* TRIGFUNCTOR                 */
#include "pvalaux.h"  /* twoparts                    */
#include "cflags.h"
#include "intsub.h"   /* linearsqrt                  */
#include "islinear.h"
#include "autosimp.h" /* get_whichpass               */
#include "limval.h"   /* contains_exp                */
#include "autocalc.h"
#include "limval2.h"  /* contains_in_exp             */
#include "gcdsub.h"   /* get_gcdsub                  */
#include "series.h"   /* intseries etc.              */
#include "limval2.h"  /* lhopital_certain            */

/* Public functions, called in automode.c */
void autodif(term, int, actualop *, int *);
void autoint(term, term *, int, actualop *, int *);
void autolimit(term, int, actualop *, int *);

static int trigpower_quotient(term u, term x);
static int pimultiple(term a);
static int odd_mul_piover2(term a);
static int polysqrt(term t, term x);
static int contains_trigsquare(term u,term x);
/*________________________________________________________________*/
void autodif(term t, int i, actualop *o, int *nops)
/* t has functor DIFF;  put into array o starting at i the operators
that might be used to simplify t; return the final value of i in *nops */
{ unsigned g;
  term u = ARG(0,t);
  int topic = get_currenttopic();
  assert(FUNCTOR(t)==DIFF);
  if(ARITY(t) == 3)  /* a higher derivative, t = diff(u,x,n) */
     { if(ISATOM(u))  /* leave d^n y/dx^n  alone when y is an atom */
          { *nops = i;
            return;
          }
       if(OBJECT(u))
          { o[i] = difconstant; ++i;
            *nops = i;
            return;
          }
       if(!PREDEFINED_FUNCTOR(FUNCTOR(u)) &&
          ISATOM(ARG(0,u))
         )
          { *nops = i;   /* leave d^n /dx^n  f(x) alone */
            return;
          }
       if(equals(ARG(2,t),two))
          { o[i] = difdif; ++i;
          }
       else
          { o[i] = difdifn; ++i;
          }
       *nops = i;
       return;
     }
  assert(ARITY(t) == 2);
  if(!get_limitflag() && get_problemtype() == DIFFERENTIATE_FROM_DEFN)
     { o[i] = defnofderivative; ++i;
       *nops = i;
       return;
     }
  o[i] = difconstant; ++i;   /* e.g.  d/dx ln(10);  argument can be complicated */
  if(ATOMIC(u))
     { o[i] = difidentity; ++i;
       *nops = i;
       return;
     }
  g = FUNCTOR(u);
  if(
      ispolyin(u,ARG(1,t))  &&
      status(difpoly)>= KNOWN
    )
     /* difpoly doesn't work on   x/a   anyway although it passes ispolyin */
     { o[i] = difpoly; ++i;
       *nops = i;
       return;
     }
  switch(g)
     { case '+' :
          o[i] = difsum; ++i;
          break;
       case '-' :
          o[i] = difminus; ++i;
          break;
       case '*' :
          o[i] = diflinear; ++i;
          if(topic == _logarithmic_differentiation ||
             ( status(logdif) >= LEARNING &&
               use_logdif(u,ARG(1,t))
             )
            )
             { o[i] = logdif; ++i;
               break;
             }
          o[i] = difproduct; ++i;
          break;
       case '/' :
          o[i] = diflinear2; ++i;
          o[i] = difinversepower; ++i;
          o[i] = difrecip; ++i;
          if(topic == _logarithmic_differentiation ||
             (status(logdif) >= LEARNING && use_logdif(u,ARG(1,t)))
            )
             { o[i] = logdif; ++i;
               break;
             }
          o[i] = difquotient; ++i;
          break;
       case '^' :
          o[i] = difpower; ++i;
          o[i] = difpower2; ++i;
          o[i] = difexp; ++i;
          o[i] = difexp2; ++i;
          o[i] = difatox; ++i;
          o[i] = difatox2; ++i;
          o[i] = difexponential; ++i;
          break;
       case ROOT:
          o[i] = difroots; ++i;
          break;
       case SQRT:
          if(topic == _logarithmic_differentiation ||
             ( status(logdif) >= LEARNING &&
               (FUNCTOR(ARG(0,u)) == '*' || FUNCTOR(ARG(0,u)) == '/') &&
               use_logdif(ARG(0,u),ARG(1,t))
             )
            )
             { o[i] = logdif; ++i;
             }
          o[i] = difsqrt; ++i;
          o[i] = difsqrt2; ++i;
          break;
       case SIN:
          o[i] = difsin; ++i;
          o[i] = difsin2; ++i;
          break;
       case COS:
          o[i] = difcos; ++i;
          o[i] = difcos2; ++i;
          break;
       case TAN:
          o[i] = diftan; ++i;
          o[i] = diftan2; ++i;
          break;
       case SEC:
          o[i] = difsec; ++i;
          o[i] = difsec2; ++i;
          break;
       case CSC:
          o[i] = difcsc; ++i;
          o[i] = difcsc2; ++i;
          break;
       case COT:
          o[i] = difcot; ++i;
          o[i] = difcot2; ++i;
          break;
       case ATAN:
          o[i] = difatan; ++i;
          o[i] = difatan2; ++i;
          break;
       case ASIN:
          o[i] = difasin; ++i;
          o[i] = difasin2; ++i;
          break;
       case ACOS:
          o[i] = difacos; ++i;
          o[i] = difacos2; ++i;
          break;
       case ACOT:
          o[i] = difacot; ++i;
          o[i] = difacot2; ++i;
          break;
       case ASEC:
          o[i] = difasec; ++i;
          o[i] = difasec2; ++i;
          break;
       case ACSC:
          o[i] = difacsc; ++i;
          o[i] = difacsc2; ++i;
          break;
       case ATANH:
          o[i] = difatanh; ++i;
          break;
       case ASINH:
          o[i] = difasinh; ++i;
          break;
       case ACOSH:
          o[i] = difacosh; ++i;
          break;
       case ACOTH:
          o[i] = difacoth; ++i;
          break;
       case ASECH:
          o[i] = difasech; ++i;
          break;
       case ACSCH:
          o[i] = difacsch; ++i;
          break;
       case LN  :
          switch(FUNCTOR(ARG(0,ARG(0,t))))
             { case ABSFUNCTOR:
                  o[i] = diflnabs; ++i;
                  o[i] = diflnabs2; ++i;
                  break;
               case COS:
                  o[i] = diflncos; ++i;
                  break;
               case SIN:
                  o[i] = diflnsin; ++i;
                  break;
               case SINH:
                  o[i] = diflnsinh; ++i;
                  break;
               case COSH:
                  o[i] = diflncosh; ++i;
                  break;
               case '/':  break;  /* use ln(a/b) = ln a - ln b first */
               case '*':  break;  /* use ln(ab) = ln a + ln b first */
               default:
                  o[i] = difln; ++i;
                  o[i] = difln2; ++i;
                  break;
             }
          break;
       case SINH:
          o[i] = difsinh; ++i;
          break;
       case COSH:
          o[i] = difcosh; ++i;
          break;
       case TANH:
          o[i] = diftanh; ++i;
          break;
       case COTH:
          o[i] = difcoth; ++i;
          break;
       case CSCH:
          o[i] = difcsch; ++i;
          break;
       case SECH:
          o[i] = difsech; ++i;
          break;
       case ABSFUNCTOR:
          o[i] = difabs; ++i;
          o[i] = difabs2; ++i;
          break;
       case SG:
          o[i] = difsg; ++i;
          break;
       case BESSELJ:
       case BESSELY:
       case BESSELI:
       case BESSELK:   break;  /* FINISH THIS */
       case SUM:
          o[i] = difsigma; ++i;
          break;
       case VECTOR:
          o[i] = difvector; ++i;
          break;
       case MATRIX:
          o[i] = difmatrix; ++i;
          break;
       case DIFF:
          if(ARITY(u)==2)
             { o[i] = secondderiv; ++i;
               break;
             }
          if(ARITY(u)==3)
             { o[i] = highderiv; ++i;
               break;
             }
          break;
       default:
          o[i] = chainrule; ++i;
          break;
     }
  *nops = i;
}
/*________________________________________________________________*/
void autolimit(term t, int i, actualop *o, int *nops)
/* t has functor LIMIT;  put into array o starting at i the operators
that might be used to simplify t; return the final value of i in *nops */
{ unsigned g,h,k;
  term u,v,a,x,num,denom;
  int lnabsflag,tflag;
  unsigned n;
  int changelimitvarflag = 0;
  assert(FUNCTOR(t)==LIMIT);
  u = LIMITAND(t);
  a = ARG(1,ARG(0,t));   /* where the limit is going to */
  x = ARG(0,ARG(0,t));   /* the limit variable */
  /* limconst, limident, and limpoly are in pre_ops */
  g = FUNCTOR(u);
  switch(g)
    { case '+' :
         o[i] = limdif; ++i;
         o[i] = limsum; ++i;
         o[i] = limsum3; ++i;  /* eliminate neg exponents in sum */
         o[i] = limsum4; ++i;  /* cot = 1/tan etc in sum         */
         if(status(sumleadingterm) >= LEARNING)
            { o[i] = sumleadingterm; ++i;
              /* example, ln(t) + 1/t + ...  */
            }
         o[i] = limsum1; ++i;  /* factor denominators            */
         o[i] = limsum2; ++i;  /* take common denom in sum       */
         o[i] = rationalizesum; ++i;
         break;
      case ABSFUNCTOR:
         o[i] = limabs;++i;
         break;
      case SUM:
         o[i] = limsum; ++i;
         break;
      case '-' :
         /* limlinear and limminus are in pre_ops */
         break;
      case '*' :
         /* limlinear is in pre_ops */
         n = ARITY(u);
         lnabsflag = tflag = 0;
         // logflag = 0;   // logflag is never actually used
         for(k=0;k<n;k++)
            { v = ARG(k,u);
              h = FUNCTOR(v);
             //  if(h== LN)
               //   ++logflag;  // it's never actually used, so never mind setting it
              if(h == ABSFUNCTOR && FUNCTOR(ARG(0,v)) == LN)
                 ++lnabsflag;
              if(h == '^' && (FUNCTOR(ARG(0,v)) == SIN || FUNCTOR(ARG(0,v))==COS))
                 ++tflag;
              if(h == SIN || h == COS)
                 ++tflag;
            }
         if(n==2 && ZERO(a) && status(limtlnt) >= LEARNING)
            { if(equals(ARG(0,u),x) && FUNCTOR(ARG(1,u)) == LN && equals(ARG(0,ARG(1,u)),x))
                  { o[i] = limtlnt; ++i;
                  }
               if(equals(ARG(0,u),x) &&
                  FUNCTOR(ARG(1,u)) == '^' &&
                  FUNCTOR(ARG(0,ARG(1,u))) == LN &&
                  equals(ARG(0,ARG(0,ARG(1,u))),x)
                 )
                  { o[i] = limtlntpower; ++i;
                  }
               if(FUNCTOR(ARG(0,u)) == '^' &&
                  equals(ARG(0,ARG(0,u)),x) &&
                  FUNCTOR(ARG(1,u)) == LN &&
                  equals(ARG(0,ARG(1,u)),x)
                 )
                  { o[i] = limtpowerlnt; ++i;
                  }
               if(FUNCTOR(ARG(0,u)) == '^' &&
                  equals(ARG(0,ARG(0,u)),x) &&
                  FUNCTOR(ARG(1,u)) == '^' &&
                  FUNCTOR(ARG(0,ARG(1,u))) == LN &&
                  equals(ARG(0,ARG(0,ARG(1,u))),x)
                 )
                  { o[i] = limtpowerlntpower; ++i;
                  }
             }
         o[i] = limprod; ++i;
         if(ARITY(u) == 2 && contains_at_toplevel(u,LN))
            { o[i] = limprod2right; ++i;
            }
         o[i] = pulloutnonzerolimit; ++i;
         if((lnabsflag) && status(lhopital) > LEARNING)
            { o[i] = limpowertimeslnabs; ++i;
            }
         if(tflag)
            { o[i] = squeezetheorem; ++i;
            }
         o[i] = createcompoundfraction; ++i;
         /* isolateln, isolatelnpower, negexptodenom, exptodenom,
            and trigtodenom are used in menu mode, but in auto
            mode createcompoundfraction does all the work of these
            operators */

         break;
      case '/' : /* limlinear is in pre_ops */
         num = ARG(0,u);
         denom = ARG(1,u);
         if(NOTDEFINED(a))
            { o[i] = inflimpower1; ++i;
            }
         if(get_currenttopic() != _lhopitals_rule)
            /* under this topic, these limits are derived */
            { o[i] = limsin1; ++i;
              o[i] = limtan1; ++i;
              o[i] = limcos1; ++i;
              o[i] = limcos2; ++i;
              o[i] = limln1;  ++i;
              o[i] = limexp1; ++i;
              o[i] = limexp2; ++i;
              o[i] = limsinh1; ++i;
              o[i] = limtanh1; ++i;
              o[i] = limcosh1; ++i;
              o[i] = limcosh2; ++i;
            }
         if(equals(a,infinity))
            { if(FUNCTOR(num) == LN &&
                 equals(ARG(0,num),x) &&
                 equals(denom,x)
                )
                 { o[i] = limlntovert; ++i;
                 }
              if(FUNCTOR(num) == '^' &&
                 FUNCTOR(ARG(0,num)) == LN &&
                 equals(ARG(0,ARG(0,num)),x) &&
                 equals(denom,x)
                )
                 { o[i] = limlntpowerovert; ++i;
                 }
              if(FUNCTOR(num) == LN &&
                 equals(ARG(0,num),x) &&
                 FUNCTOR(denom) == '^' &&
                 FUNCTOR(ARG(0,denom)) == LN &&
                 equals(ARG(0,ARG(0,denom)),x)
                )
                 { o[i] = limlntovertpower; ++i;
                 }
              if(FUNCTOR(num) == '^' &&
                 FUNCTOR(ARG(0,num)) == LN &&
                 equals(ARG(0,ARG(0,num)),x) &&
                 FUNCTOR(denom) == '^' &&
                 equals(ARG(0,denom),x)
                )
                 { o[i] = limlntpowerovertpower; ++i;
                 }
              if(FUNCTOR(denom) == LN &&
                 equals(ARG(0,denom),x) &&
                 equals(num,x)
                )
                 { o[i] = limtoverlnt; ++i;
                 }
              if(equals(num,x) &&
                 FUNCTOR(denom) == '^' &&
                 FUNCTOR(ARG(0,denom)) == LN &&
                 equals(ARG(0,ARG(0,denom)),x)
                )
                 { o[i] = limtoverlntpower; ++i;
                 }
              if(FUNCTOR(denom) == LN &&
                 equals(ARG(0,denom),x) &&
                 FUNCTOR(num) == '^' &&
                 equals(ARG(0,num),x)
                )
                 { o[i] = limtpoweroverlnt; ++i;
                 }
              if(FUNCTOR(num) == '^' &&
                 equals(ARG(0,num),x) &&
                 FUNCTOR(denom) == '^' &&
                 FUNCTOR(ARG(0,denom)) == LN &&
                 equals(ARG(0,ARG(0,denom)),x)
                )
                 { o[i] = limtpoweroverlntpower; ++i;
                 }
            }
         /* other known limits of indeterminate quotients go in here */
         o[i] = quotientofpowers; ++i;
         o[i] = multnumdenom; ++i;
         if(NOTDEFINED(a) && rational_function(u,x) &&
            get_currenttopic() != _limleadingterm
           )
            /* limits of rational functions at infinity */
            /* when a is finite, use cancelgcd, and
               when not both num and denom go to zero,
               just use limquotient */
            { if(status(limrationalfunction) >= KNOWN)
                 { o[i] = limrationalfunction; ++i;
                 }
              else if(use_leadingterms(u,x))
                 { o[i] = limleadingterms; ++i;
                   /* this will work and not look mysterious
                      when applied to a rational function */
                 }
            }
         o[i] = limrecip; ++i;
         if(!NOTDEFINED(a) && !ZERO(a) &&
            rational_function(u,x) &&
            (FUNCTOR(ARG(0,u)) == '+' || FUNCTOR(ARG(1,u)) == '+')
           )
            { o[i] = factorunderlimit; ++i;
            }
         o[i] = limquotient; ++i;
         /* limquotient fails if both num and denom go to zero
            or infinity, but it allows one of them to do so or
            one to go to zero and the other to infinity.
            Therefore, beyond this point we are dealing with
            an indeterminate form.
         */
         /* Example, lim(x->infinity, x/sqrt(x-1)).  If we bring the
            sqrt outside we get a limit of a rational function.
            Example,  lim(x->0, (ln ln x)/sqrt x). If we bring the
            sqrt outside we get an impossible mess.  Instead we
            must use L'Hospital's rule.  So use the rules for bringing
            roots out VERY sparingly.
         */

         if(FUNCTOR(num) == SQRT &&
            ispolyin(ARG(0,num),x) &&
            ispolyin(denom,x)
           )
            { o[i] = limsqrt1; ++i;
              o[i] = limsqrt2; ++i;
            }
         if(FUNCTOR(denom) == SQRT &&
            ispolyin(ARG(0,denom),x) &&
            ispolyin(num,x)
           )
            { if(status(sumleadingterm) >= LEARNING)
                 { o[i] = sumleadingterm; ++i;
                   /* example, x/sqrt(x^2+1) */
                 }
              o[i] = limsqrtdenom1; ++i;
              o[i] = limsqrtdenom2; ++i;
            }
         if(FUNCTOR(num) == ROOT &&
            ispolyin(ARG(1,num),x) &&
            ispolyin(denom,x)
           )
            { o[i] = limroot1; ++i;
              o[i] = limroot2; ++i;
            }
         if(FUNCTOR(denom) == ROOT &&
            ispolyin(ARG(1,denom),x) &&
            ispolyin(num,x)
           )
            { o[i] = limrootdenom1; ++i;
              o[i] = limrootdenom2; ++i;
            }
         if(get_currenttopic() == _lhopitals_rule &&
            !stop_lhopital(t)   /* e.g.  x-sqrt(x^2+x) needs invertlimit first */
           )
            /* example, (sin^2 x)/x, use L'Hopital under that topic */
            { o[i] = lhopital; ++i;
            }
         o[i] = pulloutnonzerolimit; ++i;
         /* pulloutnonzerolimit must precede divnumdenom, else
            divnumdenom makes complicated expressions that could
            be avoided and are hard to solve, for example in
            differentiating tan x from definition of deriv.
         */
         if(algpoly2(num) && algpoly2(denom) &&
            status(limrationalfunction) >= KNOWN
           )
            { o[i] = sumleadingterm; ++i;
            }

         if(algpoly(num) && algpoly(denom))
            { if(contains(u,SQRT) || contains(u,ROOT) ||
                 contains_fractional_exponents(u)
                )
              /* Example:  (1+sqrt(u))/(1-sqrt(u)) should be converted
                 to a rational function.  But, don't use changelimitvariable
                 on (1+x^4)/x^2 introducing u = x^2.
               */
                 { o[i] = changelimitvariable; ++i;
                   changelimitvarflag = 1;
                 }
              o[i] = divnumdenom; ++i;
            }
         /* Example: if we don't put divnumdenom before rationalizefraction:
         lim((x +  sqrt (x^2-x))/x) => lim( x/(x- sqrt (x^2-x)) => loop.   */
         /* Example: don't use divnumdenom on
         lim(x->0,(2x - arcsin x)/(2x + arccos x)).
         Use L'Hospital's rule directly.  */
         /* Note that algpoly will include the first example but not
            the second; it will also include all rational functions */

         /* Next comes 'limapartandfactor', which does this:
             (ab+ac+d)/q = a(b+c)/q + d/q
             We need this to find the derivative of sin x
             direct from the definition of derivative:
                  (sin x cos h + cos x sin h - sin x)/h  =
                  (sin x)(cos h - 1)/h + (cos x sin h)/h
             But, it makes trouble in taking limits of rational
             functions, so we forbid its use in that case; and
             if L'Hopital is known, its desirable use can be
             blocked by limapartandfactor, so don't use it
             then either.  But use it anyway if we are
             differntiating from defn.  In calc 2, L'Hopital
             is known even when differentiating from defn,
             although it isn't used then in auto mode.
          */

         if(
            !(ispolyin(num,x) && ispolyin(denom,x)) &&
            (status(lhopital) == UNKNOWN ||
             get_problemtype() == DIFFERENTIATE_FROM_DEFN
            )
           )
            { o[i] = limapartandfactor; ++i;
            }
         if(!changelimitvarflag &&
            !contains_in_exponent(u,FUNCTOR(x)) &&
            !(FRACTION(u) && trigpolyargs2(ARG(0,u),x) && ispolyin(ARG(1,u),x))
                /* example, lim(x->infinity,(x+sin(x))/(2x+3)), which
                   should be done by L'Hopital */
           )
            { o[i] = changelimitvariable; ++i;
              changelimitvarflag = 1;
              /* example, (x-16)/(x^1/4-2); this goes
                 MUCH better after u = x^1/4.  Rationalize
                 fraction will work on it and make a mess.
              */
            }
         if(status(lhopital)==UNKNOWN)
            { o[i] = rationalizefraction; ++i;
            }
         else if(ispolyin(num,x))
            { o[i] = rationalizedenom; ++i;
              /* don't rationalize num, use L'Hopital instead,
                 e.g. on lim(x->a,(root(3,x)-root(3,a)) /(x-a));
                 and don't even rationalize denom unless the
                 numerator is a polynomial, e.g. don't do it on
                 lim(x->infinity, (ln ln x)/sqrt x), where it
                 makes an unsolvable mess.
              */
            }
         if(OBJECT(num))
            { o[i] = limquoinfinite; ++i;
            }
         if(!stop_lhopital(t))
            { o[i] = lhopital; ++i;
            }
         o[i] = squeezetheorem; ++i;
         break;
      case '^' : /* defnofe is in pre_ops */
         if(equals(ARG(0,u),eulere))
            { o[i] = limcontinuous; ++i;
            }
         o[i] = limpower; ++i;
         if(equals(ARG(0,u),eulere) && is_linear_in(ARG(1,u),x))
            { /* These two operators will evaluate lim e^u even for
                 very complicated u as long as limval can compute
                 lim u to be plus or minus infinity; but we don't
                 use it unless the exponent is a linear;
                 otherwise limexponent2 should be used.
                 Example:  lim(x->infinity, e^(-x^2))
                 should not be done in one step quoting lim(x->-inf,e^x) = 0,
                 but rather in two steps, passing the limit into the
                 exponent and then quoting limit of polynomial to get
                 e^-infinity = 0.
              */

              o[i] = limexpinf; ++i;
              o[i] = limexpinf2; ++i;
            }
         if(depends(ARG(0,u),x))  /* non constant base */
            { /* examples:  x^(sin x/x) as x->0.  Don't use
                 limexptolog on this.  On the other hand
                 x^x HAS to be written e^x log x.
                 The operator limexponent will work in
                 automode only if the limit of the base
                 is defined and, if it's zero, the limit
                 of the exponent is not zero; or if the
                 limit of the base is infinity and the
                 limit of the exponent is defined and not zero.
                   On the other hand, limexptolog will work
                 on anything it gets, as long as the base is
                 positive and not eulere, provided the
                 problemtype is not DIFFERENTIATE_FROM_DEFN,
                 where L'Hopital's rule is not allowed.
                 In that case it won't work if the limit
                 tends to the form 1^infinity.
              */
              o[i] = limexponent; ++i;
              o[i] = limexptolog; ++i;
            }
         else
            { o[i] = limexponent2; ++i;
            }
         if(NOTDEFINED(a))
            { o[i] = inflimpower1; ++i;
              o[i] = inflimpower2; ++i;
              o[i] = limthruexp; ++i;
            }
         o[i] = liminverseevenpower; ++i;
         o[i] = liminverseoddpower; ++i;
         o[i] = lim1inverseleft; ++i;
         o[i] = lim1inverseright; ++i;
         if(NOTDEFINED(a))
            { o[i] = limrecip; ++i;
            }  /* introduce infinite limits in denominator only
                  as a last resort */
         break;
      case ROOT:
         o[i] = limoddroot; ++i;
         o[i] = limevenroot; ++i;
         if(ISINFINITE(a))
            { o[i] = limrootinf; ++i;
            }
         break;
      case SQRT:
         o[i] = limsqrt; ++i;
         if(ISINFINITE(a))
            { o[i] = limsqrtinf; ++i;
            }
         break;
      case LN:
         o[i] = limlnsing; ++i;
         if(! (equals(a,infinity) && equals(u,x)) &&
            /* lim(x->infinity, ln x) is handled directly rather
               than as ln(lim(x->infinity,x) = ln(infinity) = infinity */
            ! (FRACTION(ARG(0,u)) && ONE(ARG(0,ARG(0,u))))
               /* lim ln(1/v) = -lim ln v is better */
           )
            { o[i] = limthrulog; ++i;
            }
         if(ISINFINITE(a))
            { o[i] = limlnright; ++i;
            }
         break;
      case SIN:
         o[i] = limoscsin; ++i;
         if(ISINFINITE(a))
            { o[i] = liminfsin; ++i;
            }
         o[i] = limthrusin; ++i;
         break;
      case COS:
         o[i] = limosccos; ++i;
         if(ISINFINITE(a))
            { o[i] = liminfcos; ++i;
            }
         o[i] = limthrucos; ++i;
         break;
      case TAN:
         o[i] = limtansing; ++i;
         o[i] = limosctan; ++i;
         if(ISINFINITE(a))
            { o[i] = liminftan; ++i;
            }
         break;
      case COT:
         if(ISINFINITE(a))
            { o[i] = cottotan; ++i;
            }
         o[i] = limcotsing; ++i;
         break;
      case SEC:
         if(ISINFINITE(a) || odd_mul_piover2(a))
            { o[i] = secrule; ++i;
            }
         o[i] = limsecsing; ++i;
         break;
      case CSC:
         if(ISINFINITE(a) || pimultiple(a))
            { o[i] = cscrule; ++i;
            }
         o[i] = limcscsing; ++i;
         break;
      case ATAN:
         if(ISINFINITE(a))
            { o[i] = limarctaninf; ++i;
            }
         break;
      case TANH:
         if(ISINFINITE(a))
            { o[i] = limtanhinf; ++i;
            }
         break;
    }
  if(ARITY(u) == 1 && FUNCTOR(u) != '-' &&
     FUNCTOR(ARG(0,u)) == '^' &&
     equals(ARG(0,ARG(0,u)),eulere) &&
     !changelimitvarflag
    )
     /* example, lim(x->infinity, cos(e^-x)) */
     { o[i] = changelimitvariable; ++i;
       changelimitvarflag = 1;
     }
  /* we also need to use changelimitvariable on lim(x->0, (1-e^(-x))/x),
     and also lim(x->0, (1-e^(cx))/x).  This only is used in
     problemtype DIFFERENTIATE_FROM_DEFN where L'Hopital is forbidden. */
  if(!changelimitvarflag &&
     ZERO(a) && FRACTION(u) && equals(ARG(1,u),x) &&
     FUNCTOR(ARG(0,u)) == '+' && ARITY(ARG(0,u)) == 2 &&
     ONE(ARG(0,ARG(0,u))) && NEGATIVE(ARG(1,ARG(0,u))) &&
     FUNCTOR(ARG(0,ARG(1,ARG(0,u)))) == '^' &&
     equals(ARG(0,ARG(0,ARG(1,ARG(0,u)))), eulere)
    )
     { o[i] = changelimitvariable; ++i;
       changelimitvarflag = 1;
     }
  if(!NOTDEFINED(a))
     { o[i] = limcontinuous; ++i;  /* FINISH THIS Make this usable at infinity too */
     }
  if(!changelimitvarflag &&
     !(FRACTION(u) && trigpolyargs2(ARG(0,u),x) && ispolyin(ARG(1,u),x)) &&
     /* example, lim(x->infinity,(x+sin(x))/(2x+3)), which
        should be done by L'Hopital */
     (!contains_in_exponent(u,FUNCTOR(x)) || contains_in_exponent(u,'/') || !ISINFINITE(a))
    )
     { o[i] = changelimitvariable; ++i;  /* This can be used at infinity,
                                     but don't introduce 1/x in the exponent */
       changelimitvarflag = 1;
     }
  if(NOTDEFINED(a) &&
     !contains_exp(u,x) &&
     !contains_in_exponent(u,FUNCTOR(x)) &&
     !contains_calc(u) &&   // no integrals or derivatives in the limitand;  it will fail anyway in those cases
     /* don't use invertlim if it will create e^(1/x). */
     !(FRACTION(u) && ispolyin(ARG(0,u),x) && ispolyin(ARG(1,u),x))
     /* Use L'Hopital instead of invertlim in that case, e.g.  (x + sin x)/(x+3)*/
    )
     { o[i] = invertlim; ++i;
     }
  else if(ISINFINITE(a) && FUNCTOR(u) == '+' && polysqrt(u,x) && !contains_calc(u))
      /* poly(x) - sqrt(poly(x)) needs invertlimit,
         unless rationalizesum works, or changelimitvariable works as in sqrt(1+x^2) - root(4,x)  */
     { o[i] = invertlim; ++i;
     }
  if(
     get_whichpass() > 1 ||
     (get_whichpass() == 1 && !contains_hypertrig(u))
    )
    /* as a last resort use leading terms; when whichpass is 1 we still
       don't use it as hypertrig functions don't get expanded to
       exponentials until whichpass is 2.
    */
     { if(g == '/')
          { o[i] = limleadingterms; ++i;
          }
       else if(g == '+')
          { o[i] = sumleadingterm; ++i;
          }
       else
          { o[i] = limleadingterm; ++i;
          }
     }
  *nops = i;
}
/*________________________________________________________________*/
void autoint(term t, term *arg, int i, actualop *o, int *nops)
/* t has functor INTEGRAL;  put into array o starting at i the operators
that might be used to simplify t; return the final value of i in *nops
*/
{ unsigned short g,h;
  unsigned short const * path = get_path();
  term u,v,x,a,b,power,newpower,num,denom;
  int currenttopic = get_currenttopic();
  int problemtype = get_problemtype();
  int pathlength = get_pathlength();
  int j;
  if(problemtype == POWERSERIES)
     {  o[i] = intseries; ++i;   // integrate power series term by term 
        /* don't try to evaluate an integral that was just introduced by f = integral(diff(f,x),x);
          but after the derivative is expanded in a series and the integral is pushed into the series, it 
          will need to be evaluated.  So,  SUM should be on the path.  */
        for(j=0;j<pathlength; ++j)
           { if(path[j] == SUM)
                break;
           }
        if(j==pathlength && !contains(t,SUM))
           { /*  this integral isn't inside SUM, so don't try to evaluate it until the 
                 integrand has been expanded in a series. */
             *nops = i;
             return;
           }
     }
  assert(FUNCTOR(t)==INTEGRAL);
  u = ARG(0,t);  /* the integrand */
  x = ARG(1,t);  /* the variable of integration */
  if(ARITY(t) == 4 && equals(ARG(2,t),ARG(3,t)))
     { o[i] = integrateemptyinterval; ++i;
       *nops = i;
       return;
     }
  if(ATOMIC(u))
     { o[i] = int1; ++i;
       o[i] = intconst; ++i;
       o[i] = intident; ++i;
       *nops = i;
       return;
     }
  if(ARITY(t) == 4 && contains(u,ABSFUNCTOR) && FUNCTOR(u) != ABSFUNCTOR)
     { o[i] = insertpoint; ++i;
       /* when FUNCTOR(u) == ABSFUNCTOR, breakabsint is used. */
     }
  if(!contains(u,FUNCTOR(x)))
     { o[i] = intconst; ++i;  /* example:  u = sin 3  */
       *nops = i;
       return;
       /* even if u does depend on x indirectly by definitions,
          none of the integration operators below will help. */
     }
  if(contains(u,SG))
     { o[i] = sgint; ++i;
     }
  g = FUNCTOR(u);

       /* intpoly is in preops, so polynomials are integrated already if
          intpoly is KNOWN */
      /*  odd powers of sec x (more than 3) have to use intsecpower;
          sec^3 x can be done by parts;
          as can products sec^n x  tan^m x where n is odd and m is even
          We have to trap these special cases and might as well do it
          sooner as later. */

  if( g=='^' && !matchstring(u,x,"^(sec(x),a)",&a)  &&
      INTEGERP(a) && ISODD(a)
    )
     { if(equals(a,three) &&
          status(intsecpower) == UNKNOWN &&
          equals(t,history(get_currentline()))   /* so equatetoproblem can work */
         )
          { value(sum(a,tnegate(two)),&newpower);
            *arg = make_power(ARG(0,u),newpower);
            o[i] = integratebyparts; ++i;
            *nops = i;
            return;
          }
       o[i] = intsecpower; ++i;
       *nops = i;
       return;
     }
  switch(g)
     {  /* intminus, intsum, intlinear are in pre_ops */
       case '^' :
          v = ARG(0,u);
          h = FUNCTOR(v);
          power = ARG(1,u);
          if(equals(power,minusone))
             { if(equals(v,x))
                   { o[i] = intrecip; ++i;
                   }
               else if(FUNCTOR(v) == '+' &&
                       (equals(ARG(0,v),x) || equals(ARG(ARITY(v)-1,v),x))
                      )
                  { o[i] = intrecip2; ++i;
                  }
               else
                  { o[i] = intrecip3; ++i;
                  }
             }
          o[i] = intpower; ++i;
          if(!depends(v,x) &&
             !equals(power,x) &&  /* c^x is integrated by a special rule */
             depends(power,x)
            )
             { o[i] = intexponential; ++i;
             }
          if(equals(v,eulere))
             { if(equals(power,x))
                  { o[i] = intexp1; ++i;   /* integral e^t dt = e^t           */
                  }
               if(FUNCTOR(power) == '*')
                  { o[i] = intexp2; ++i;   /* integral e^at dt =(1/a) e^(at)  */
                  }
               if(NEGATIVE(power))
                  { o[i] = intexp3; ++i;   /* integral e^(-t)dt = -e^(-t)     */
                    o[i] = intexp4; ++i;   /* integral e^(-at)dt = -(1/a) e^(-at) */
                  }
               if(FRACTION(power))
                  { o[i] = intexp5; ++i;   /* integral e^(t/a)dt = a e^(t/a)   */
                  }
               o[i] = inttoerf; ++i;  /* integral e^(-t^2) dt =  sqrt pi/2 Erf(t) */
             }
          else
             { o[i] = intexp6; ++i;   /* integral c^t dt = (1/ln c) c^t  */
             }
          break;

       case '/' :
          if(polyquo(u,x))  /* rational function in quotient-of-polynomials form */
             { if(!contains(ARG(0,u),FUNCTOR(x)))
                  { term denom = ARG(1,u);
                    if(equals(denom,x))
                       { o[i] = intrecip; ++i;
                       }
                    else if(FUNCTOR(denom) == '+' &&
                            (equals(ARG(0,denom),x) || equals(ARG(ARITY(denom)-1,denom),x))
                           )
                       { o[i] = intrecip2; ++i;
                       }
                    else
                       { o[i] = intrecip3; ++i;
                       }
                    o[i] = intinversepower; ++i;
                    o[i] = inttoatan; ++i;
                  }
               if(FRACTION(u) && equals(ARG(0,u),x))
                  { o[i] = intsub; ++i;
                    /* example:  x/(x^2+1)   */
                  }
               *nops = i;
               return;  /* Don't try substitution. Without this it
                        tries u = x+1 on  integral((x+1)/(x^3-x+1),x) */
             }
          denom = ARG(1,u);
          num = ARG(0,u);
          if(FUNCTOR(denom) == '^' &&
             equals(ARG(0,denom),x) &&
             !contains(num,FUNCTOR(x)) &&
             !contains(ARG(1,denom),FUNCTOR(x))
             )
              { o[i] = intinversepower; ++i;
              }
          if(FUNCTOR(denom) == '+' && ARITY(denom) == 2 &&
             (ONE(ARG(0,denom)) || ONE(ARG(1,denom)))
            )  /*   given 1/(1-cos x), multiply num and denom by (1+cos x) */
             { term p = ONE(ARG(0,denom)) ? ARG(1,denom) : ARG(0,denom);
               term q;
               if(NEGATIVE(p))
                  { q = ARG(0,p);
                    if(FUNCTOR(q) == COS && equals(ARG(0,q),x))
                       { o[i] = trigrationalizedenom1; ++i;
                       }
                    else if(FUNCTOR(q) == SIN && equals(ARG(0,q),x))
                       { o[i] = trigrationalizedenom2; ++i;
                       }
                  }
               else if(FUNCTOR(p) == COS && equals(ARG(0,p),x))
                  { o[i] = trigrationalizedenom4; ++i;
                  }
               else if(FUNCTOR(p) == SIN && equals(ARG(0,p),x))
                  { o[i] = trigrationalizedenom5; ++i;
                  }
             }
          if(is_sincos(num,x) == -1 && is_sincos(denom,x)==1)
             { /* example:  (sin x - cos x)/(sin x + cos x) */
               o[i] = trigrationalizedenom3; ++i;
               /* In this case it's better to multiply by cos x + sin x
                  than by cos x - sin x though both will work */
             }
          if(is_sincos(num,x) == 1 && is_sincos(denom,x) == -1)
             { o[i] = trigrationalizedenom6; ++i;
             }
          if(is_sincos(denom,x) == -1)
             { o[i] = trigrationalizedenom3; ++i;
             }
/*  Example:  1/(sin x + cos x).   This can be done by
   multiplying num and denom by (sin x - cos x), then multiplying out
   in the denom, then using apart and a suitable substitution.  But
   it's better just to use the Weierstrass substitution to start with.

          if(is_sincos(denom,x) == 1)
             { o[i] = trigrationalizedenom6; ++i;
             }
*/
          if(trigpower_quotient(u,x))
             { if(currenttopic == _int_by_substitution)
                  { o[i] = choosesubstitution; ++i;
                  }
               trigpowers(t,i,o,nops);
               return;
             }
          break;

       case '*' :
          if(trigpower(u,x))
             /* sin^m x  cos^n x or sec^n x tan^m x */
             { if(currenttopic == _int_by_substitution)
                  { o[i] = choosesubstitution; ++i;
                    /* Give it a chance--if it can't work the
                       ops thrown in by trigpowers will do it,
                       but they do one-step substitutions,
                       while under this topic we want multi-step
                       solutions. */
                  }
               trigpowers(t,i,o,nops);
               return;
             }
          if(ARITY(u) == 2 && FUNCTOR(ARG(0,u)) == SEC &&
             FUNCTOR(ARG(1,u)) == TAN &&
             status(intsub) > LEARNING
            )
             { o[i] = inttosec2; ++i;
               /* If inttosec could work it would have gone under trigpowers */
             }
          if(ARITY(u) == 2 && FUNCTOR(ARG(0,u)) == CSC &&
             FUNCTOR(ARG(1,u)) == COT &&
             status(intsub) > LEARNING
            )
             { o[i] = inttocsc2; ++i;
               /* If inttocsc could work it would have gone under trigpowers */
             }
          if(ARITY(t) == 4)
             { o[i] = breakabsint; ++i;
             }
          if(ARITY(u) == 2 && FUNCTOR(ARG(1,u)) == '^' &&
             equals(ARG(1,ARG(1,u)),two) && FUNCTOR(ARG(0,ARG(1,u))) == SIN
            )
             /* Example, integral(x sin^2 x,x).  We have to
                integrate this by changinging sin^2 x to (1-cos(x/2)),
                but for example
                        integral(x sin^2 x cos x,x)
                is NOT done this way, but by parts.  So this can't be
                controlled down in the integrand; I had to make sinsqhalf2
                work on an integral to handle these examples correctly,
                calling set_pathtail to make it look like the sin^2 term
                is worked on.
             */
             { o[i] = sinsqhalf2; ++i;
             }
          break;

       case SQRT:
          o[i] = intsqrt; ++i;
          break;
       case SIN:
          o[i] = intsin; ++i;
          if(status(intsub) > LEARNING)
             { o[i] = intsin2; ++i;
             }
          break;
       case COS:
          o[i] = intcos; ++i;
          if(status(intsub) > LEARNING)
             { o[i] = intcos2; ++i;
             }
          break;
       case TAN:
          o[i] = inttan; ++i;
          if(status(intsub) > LEARNING)
             { o[i] = inttan2; ++i;
             }
          break;
       case SEC:
          o[i] = intsec; ++i;
          if(status(intsub) > LEARNING)
             { o[i] = intsec2; ++i;
             }
          break;
       case CSC:
          o[i] = intcsc; ++i;
          if(status(intsub) > LEARNING)
             { o[i] = intcsc2; ++i;
             }
          break;
       case COT:
          o[i] = intcot; ++i;
          if(status(intsub) > LEARNING)
             { o[i] = intcot2; ++i;
             }
          break;
       case LN  :
          if(currenttopic != _int_by_parts1 &&
             currenttopic != _int_by_parts2
            )
             { o[i] = intln; ++i;
             }
          break;
       case SINH:
          o[i] = intsinh; ++i;
          break;
       case COSH:
          o[i] = intcosh; ++i;
          break;
       case TANH:
          o[i] = inttanh; ++i;
          break;
       case COTH:
          o[i] = intcoth; ++i;
          break;
       case CSCH:
          o[i] = intcsch; ++i;
          break;
       case SECH:
          o[i] = intsech; ++i;
          break;
       case SG:
          o[i] = intsg; ++i;
          break;
       case ABSFUNCTOR:
          o[i] = intabs; ++i;
          o[i] = breakabsint; ++i;
          break;
       /* No formulas for integrating  these--
           ATAN, ASIN, ACOS can be done by parts */
       case ATAN:
       case ASIN:
       case ACOS:
       case BESSELJ:
       case BESSELK:
       case BESSELI:
       case BESSELY:
          break;  /* FINISH THIS */
       case SUM:
          o[i] = intsigma; ++i;
          break;
       case VECTOR:
          o[i] = intvector; ++i;
          break;
       case MATRIX:
          o[i] = intmatrix; ++i;
          break;
     }
  if(status(simpleint) >= KNOWN)
      { o[i] = simpleint; ++i;}
       /* you have to try intsub even if simpleint has failed, e.g. to
       get integral(cos^2(2x),x), because after the substitution some trig
       work is required that simpleint doesn't do. */

  if(g == '^' && ISINTEGER(ARG(1,u)) && !islinear(ARG(0,u),x,&a,&b))
      { if(linearsqrt(ARG(0,u),x)&& (get_whichpass() || status(intsub) > UNKNOWN ))
           /*  (1 + sqrt x)^n can be done by substitution */
           { o[i] = intsub; ++i;
           }
        else
           { o[i] = expandintegrand; ++i;
             /* integral(x^3-1)^2,x) dx for example */
           }
      }
  if(possible_trigsub(u,x))
     { o[i] = trigsubsin; ++i;
       o[i] = trigsubtan; ++i;
       o[i] = trigsubsec; ++i;
       /* we don't use the hypertrig substitutions in auto mode */
     }
  else if(use_trigsubtan(u,x))  /* catch 1/(a^2+x^2)^n   */
     { o[i] = trigsubtan; ++i;
     }
  else if(use_trigsubsec(u,x))
     { o[i] = trigsubsec; ++i;
     }
  if(status(intsub) >= KNOWN)
      { if((g != '/' && g!= '*') || !intsub_in_preops(u,x))
           { o[i] = intsub; ++i;
           }
      }
  else if(status(intsub) >= LEARNING)
      { if( (g != '/' && g != '*') || !intsub_in_preops(u,x))
           { o[i] = choosesubstitution; ++i;
           }
           /* trysubstitution and changeintegrationvariable are in pre_ops */
      }
  o[i] = equatetoproblem; ++i;  /* BEFORE integratebyparts, to prevent infinite
                                   regress on e.g. e^x sin x */

  if(g == '*' || g == '^' || g == '/')
      { o[i] = expandintegrand; ++i;}
  if(g == '*' || g == '/')
      { o[i] = multiplyoutintegrand; ++i;}
  /* u = x e^(-x^2)  for example gets here */
  if(g == '*' && ARITY(u) == 2 && ispolyin(ARG(0,u),x) 
              && FUNCTOR(ARG(1,u)) == '^' && equals(ARG(0,ARG(1,u)),eulere)
              && ispolyin(ARG(1,ARG(1,u)),x)
    )
       {o[i] = intsub; ++i;
       }

  /* trig (or hypertrig) substitutions are used on integrands
  containing a square root of a quadratic.  By this time completethesquare1
  has done its work, so the quadratic will have no linear term.
  Use the Weierstrass substitution on rational functions of trig functions.
  The Weierstrass substitution will also apply to more general
  integrands, however integration by parts must be tried first,
  e.g.  sin(x) ln (cos x)  becomes a mess if you use Weierstrass,
  but works in one step by parts.
     On the other hand,  some integrands will satisfy trigpoly2 but are
  done by parts, for example x/cos(x).  But these won't pass stricttrigpoly2.
  */

  if(FRACTION(u) && stricttrigpoly2(ARG(0,u),x) && stricttrigpoly2(ARG(1,u),x))
     { o[i] = weierstrass; ++i;
       *nops = i;
       return;
     }

  /* Now, we DON'T want to ALWAYS try integration by parts, because in most
     cases it just leads to a mess.  In case u is a product, the operator
     itself rejects cases that look unpromising.  Sometimes it works
     on a quotient, e.g. (ln x)/x;  sometimes it works on a power,
     e.g (ln x)^2.  Otherwise the only hope is if  integral(x du/dx, x)
     can be done.  That does sometimes happen, e.g. with u  = ln x
     or u = arctan x, but some cases should be rejected as hopeless.
     Indeed, unless du/dx is a rational function or a function of x^2 it
     seems hopeless.  These rather complicated rejections are handled
     by the operator itself; here we only reject the case of an
     absolute value.
  */
  path = get_path();
  if(g != ABSFUNCTOR && status(integratebyparts) >= LEARNING &&
     path[0] != '='  /* after equatetoproblem, don't keep on integrating by parts */
    )
      { o[i] = integratebyparts; ++i;
      }

  if(ftrig(u,x) && !contains(u,ABSFUNCTOR) && !contains(u,SG))
     { o[i] = weierstrass; ++i;
     }
  h = contains_trigsquare(u,x);
  if(h) /* example,  integral (x cos^2 x,x)  gets here */
     { switch(h)
          { case CSC:
                o[i] = intcscsq; ++i;
                if(status(intsub) > LEARNING)
                   { o[i] = intcscsq2; ++i;
                   }
                o[i] = intsubcot; ++i;
                break;
             case COT:
                o[i] = intcotsq; ++i;
                if(status(intsub) > LEARNING)
                   { o[i] = intcotsq2; ++i;
                   }
                break;
             case SEC:
                o[i] = intsecsq; ++i;
                if(status(intsub) > LEARNING)
                   { o[i] = intsecsq2; ++i;
                   }
                o[i] = intsubtan; ++i;
                break;
             case TAN:
                o[i] = inttansq; ++i;
                if(status(intsub) > LEARNING)
                   { o[i] = inttansq2; ++i;
                   }
                break;
             case SIN:
                o[i] = intsinsq; ++i;
                o[i] = intsubcos; ++i;
                break;
             case COS:
                o[i] = intcossq; ++i;
                o[i] = intsubsin; ++i;
                break;
           }
     }
  *nops = i;
}


/*____________________________________________________________*/
int trigpower(term u, term x)
/* return 1 if u is a product sin^n x cos^m x (n,m = 1 allowed,
but not n,m = 0), or sec^n x tan^m x; or with the other order
of the factors. */

{ term a,b;
  unsigned f,h;
  if(FUNCTOR(u) != '*' || ARITY(u) != 2)
     return 0;
  a = ARG(0,u);
  b = ARG(1,u);
  f = FUNCTOR(a);
  if( f == '^' && INTEGERP(ARG(1,a)))
      { a = ARG(0,a);
        f = FUNCTOR(a);
      }
  h = FUNCTOR(b);
  if( h == '^' && INTEGERP(ARG(1,b)))
     { b = ARG(0,b);
       h = FUNCTOR(b);
     }
  if(ARITY(a) != 1 || ARITY(b) != 1)
     return 0;
  if(f != SIN && f != COS && f != TAN && f != SEC)
     return 0;
  if(h != SIN && h != COS && h != TAN && h != SEC)
     return 0;
  if(!equals(ARG(0,a),x) || !equals(ARG(0,b),x))
     return 0;
  if( (h == SIN && f == COS) ||
      (h == COS && f == SIN) ||
      (h == TAN && f == SEC) ||
      (h == SEC && f == TAN)
    )
      return 1;
  return 0;
}
/*____________________________________________________________*/
static int trigpower_quotient(term u, term x)
/* return 1 if u is a quotient sin^n x/cos^m x (n,m = 1 allowed,
and n = 0, but not m = 0), or  cos^m x/ sin^n x (in which case m=0
is allowed but not n = 0). Here n and m must be specific
positive integers. Similarly for tan and sec, cot and csc.
Return 0 if u is not such a quotient.
*/

{ term a,b;
  unsigned f,h;
  if(FUNCTOR(u) != '/')
     return 0;
  a = ARG(0,u);
  b = ARG(1,u);
  f = FUNCTOR(a);
  h = FUNCTOR(b);
  if(ONE(a))
     { if(h == '^' && INTEGERP(ARG(1,b)))
          { b = ARG(0,b);
            h = FUNCTOR(b);
          }
       if(TRIGFUNCTOR(h) && equals(ARG(0,b),x))
           return 1;
       return 0;
     }
  if( f == '^' && INTEGERP(ARG(1,a)))
      { a = ARG(0,a);
        f = FUNCTOR(a);
      }
  h = FUNCTOR(b);
  if( h == '^' && INTEGERP(ARG(1,b)))
     { b = ARG(0,b);
       h = FUNCTOR(b);
     }
  if(ARITY(a) != 1 || ARITY(b) != 1)
     return 0;
  if(!((f == SIN && h == COS) || (f == COS && h == SIN)) &&
     !((f == SEC && h == TAN) || (f == TAN && h == SEC)) &&
     !((f == CSC && h == COT) || (f == COT && h == CSC))
    )
     return 0;
  if(!equals(ARG(0,a),x) || !equals(ARG(0,b),x))
     return 0;
  return 1;
}
/*__________________________________________________________________*/
/*  Strategy for trig power integrands  sin^n  cos^m  (including n or m zero)
  1.  m odd:  write cos^2 in terms of sin and substitute u = sin x.
  2.  n odd:  write sin^2 in terms of cos and substitute u = cos x.
  3.  Both n and m even:  write sin^2 and cos^2 in terms of cos 2x.
      This reduces to an integral of the same form but with lower
      power.

    Strategy for trig power integrands tan^n sec^m  (including n or m zero)
  4.  m even > 0:  save out one sec^2 and write the rest in terms of tan^2.
  5.  m odd > 0 and n > 0:
          save out sec tan and write the rest in terms of sec^2.
  6.  m == 0, n even:  write tan^2 = sec^2-1, so we get (sec^2-1)^k;
      expand by the binomial theorem getting integrals involving
      only sec, see below.
  7.  m == 0, n odd:  write tan^2 = sec^2-1, so we get (sec^2-1)^k tan,
      reducing to case 4 except for the last term integral(tan x, x),
      which is ln(abs(sec x)).
  8.  m == 1, n==0:   integral(sec x,x) = ln abs(sec x + tan x)
  9.  m odd > 1, n==0:  Use a reduction formula (obtained by
      integrating by parts)  to reduce to a sum of integrals,
      one with  m  decreased and n zero, one with m the same but n > 0,
      which can be done by case 5.  You have to keep iterating
      this reduction formula; you don't get a closed formula for
      the answer.

    Strategy for trig power integrands sin^n / cos^m  or cos^m/sin^m (n !=m)

  10. if n odd, set u = cos x;
  11. if m odd, set u = sin x
  12. If both even, proceed as in case 3.

In autoint, the cases where m or n is zero are handled separately,
and the cases m and n both nonzero come to the following function for
a decision what to do.
*/

/*____________________________________________________________*/
void trigpowers(term t, int i, actualop *o, int *nops)
/* finish autoint when the integrand is a product of
trigonometric powers,  sin^m cos^n or sec^m tan^n; or a
quotient of powers sin^m /cos^n or cos^m / sin^n, or a reciprocal
of a trig function or a reciprocal of a power of a trig function.
Outputs are the same as for autoint. */
/* Powers of a single trig function are dealt with in pre_ops */

{ term u = ARG(0,t);       /* the integrand               */
  term p,q,n,m;            /* u = p^n q^m or p^n/q^n      */
  term swap;
  int swapflag = 0;
  term x = ARG(1,t);       /* the variable of integration */
  unsigned f,h,ff;
  assert(FUNCTOR(u) == '*' || FUNCTOR(u) == '/');
  assert(ARITY(u) == 2);
  p = ARG(0,u);  /* temporarily */
  q = ARG(1,u);
  f = FUNCTOR(p);
  h = FUNCTOR(q);
  if(FRACTION(u) && ONE(p) && TRIGFUNCTOR(h) && equals(ARG(0,q),x))
     { /* reciprocals of trig functions */
       switch(h)
          { case SIN:
               o[i] = intsubcos; ++i;
               break;
            case COS:
               o[i] = intsubsin; ++i;
               break;
            case TAN:
               o[i] = intsubsec; ++i;
                /* dx/tan x =  tan x sec x dx/ tan^2 x = du/(u^2-1) with u = sec x */
               break;
            case SEC:
               o[i] = secrule; ++i;
               break;
            case CSC:
               o[i] = cscrule; ++i;
               break;
            case COT:
               o[i] = cottotan; ++i;
               break;
          }
     }
  if(FRACTION(u) && ONE(p) && h == '^' &&
     TRIGFUNCTOR(FUNCTOR(ARG(0,q)))
    )
     { switch(FUNCTOR(ARG(0,q)))
          { case SIN:
               o[i] = cscrule2; ++i;
               break;
            case COS:
               o[i] = secrule2; ++i;
               break;
            case TAN:
               o[i] = tanrecip; ++i;
               break;
            case COT:
               o[i] = cotrecip; ++i;
               break;
            case SEC:
               o[i] = secrecip; ++i;
               break;
            case CSC:
               o[i] = cscrecip; ++i;
               break;
          }
     }
  if(f == '^')
     { f = FUNCTOR(ARG(0,p));
       n = ARG(1,p);
       p = ARG(0,p);
     }
  else
     n = one;
  if( h == '^')
     { h = FUNCTOR(ARG(0,q));
       m = ARG(1,q);
       q = ARG(0,q);
     }
  else
     m = one;
  /* Now u = p^n q^m as advertised, or p^n/q^m */

    if(!equals(ARG(0,p),x) || !equals(ARG(0,q),x))
       { *nops = i;
         return;
       }

  if(f == COS && h == SIN)
     { swap = p; p=q; q = swap;   /* interchange p and q */
       swap = m; m=n; n = swap;   /* interchange m and n */
       ff = f; f = h; h = ff;     /* interchange f and h */
       swapflag = 1;
     }
  if(f == TAN && h == SEC)
     { swap = p; p=q; q = swap;   /* interchange p and q */
       swap = m; m=n; n = swap;   /* interchange m and n */
       ff = f; f = h; h = ff;     /* interchange f and h */
       swapflag = 1;
     }
  if(f == COT && h == CSC)
     { swap = p; p=q; q = swap;   /* interchange p and q */
       swap = m; m=n; n = swap;   /* interchange m and n */
       ff = f; f = h; h = ff;     /* interchange f and h */
       swapflag = 1;
     }

  if(f == SIN && h == COS && ISEVEN(n) && ISEVEN(m))
     { o[i] = intsinsq; ++i;  /* use half-angle identities */
       o[i] = intcossq; ++i;
       *nops = i;
       return;
     }
  if(f == SIN && h == COS && ISODD(m) && ISODD(n))
      /*  get integral( sin x cos^m, x) and integral( sin^n  x cos x, x)
          done with the simplest substitution */
     { short order;
       tcompare(m,n,&order);
       if(ONE(n) || ONE(m))
          { o[i] = intsub; ++i;  /* just use u = sin(x) or u = cos(x),
                            no need to use a trig square identity first */
          }
       else if(order == 1)   /* n < m */
          { o[i] = intsubcos; ++i;
          }
       else
          { o[i] = intsubsin; ++i;
          }
       *nops = i;
       return;
     }
  if(f == SIN && h == COS && ISODD(m))
     { o[i] = intsubsin; ++i;
       *nops = i;
       return;
     }
  if(f == SIN && h == COS && ISODD(n))
     { o[i] = intsubcos; ++i;
       *nops = i;
       return;
     }

  assert((f==SEC && h==TAN) || (f==CSC && h==COT));

  if(iseven(n))   /* even power of secant */
     { o[i] = f==SEC ? intsubtan : intsubcot; ++i;
       *nops = i;
       return;
     }
  if(ONE(m))   /*  sec^n  x tan x  */
     { if(ONE(n))
          { o[i] = f == SEC ? inttosec : inttocsc; ++i;
          }
       o[i] = f == SEC ? intsubsec : intsubcsc; ++i;
       *nops = i;
       return;
     }
  if(isodd(m))   /*  sec^n  x tan^odd x  */
      { o[i] = f == SEC ? tantosecinint : cottocscinint; ++i;
        set_expandflag(0x100); /* expand the powers of 1-sec^2 */
        set_factorflag(0);  /* and don't loop */
        *nops = i;
        return;
      }
  if(isodd(n))  /* odd power of sec, even power of tan */
     { if(FUNCTOR(u) == '/')
          /* write everything in terms of sin and cos; it will
             suffice to rewrite the denominator, then the usual
             trig code will rewrite the num; but since only
             tan and sec (or cot and csc) occur, we have to give
             it a kick before anything will happen */
          { if(swapflag)
               { o[i] = f == SEC ? secrecip : cscrecip; ++i;
               }
            else
               { o[i] = f == SEC ? tanrecip2 : cotrecip2; ++i;
               }
          }
       else
          { o[i] = f == SEC ? tantosecinint : cottocscinint; ++i;
          }
       *nops = i;
       return;
     }
  assert(0);  /* all cases in which it's called should be covered */
}

/*___________________________________________________*/
static int complicated(term t)
/* return a measure of how complicated t is.  This counts the number of
sums occurring as factors of t, counting powers of sums according to the
power, but powers 5 or more all count 5. */

{ int count;
  unsigned n,i;
  term u;
  long power;
  unsigned f = FUNCTOR(t);
  if(f == '^' && FUNCTOR(ARG(0,t)) == '+')
     { if(ISINTEGER(ARG(1,t)))
          { power = INTDATA(ARG(1,t));
            if(power >= 5)
                return 5;
            return (int) power;
          }
       return 0;   /* can't actually get here */
     }
  if(f == '*')
     { n = ARITY(t);
       count = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == '+')
               count += complicated(u);
            if(FUNCTOR(u) == '+')
               ++count;
          }
       return count;
     }
  if(f == '+')
     return ARITY(t)-1;
  return 0;
}
/*___________________________________________________*/
/* x isn't used; but maybe it will be in the future if this
needs to be made more sophisticated */
int use_leadingterms(term u, term x)
/* u is a rational function of x.  To calculate a limit of u
at infinity or minusinfinity, should we use
the operator limleadingterms? or should we try divnumdenom and limquo?
Return 1 if we should use limleadingterms, e.g. if it's KNOWN or
if it looks like divnumdenom might lead to out-of-memory errors
We DO use it on very complicated rational functions no matter what
its status is.
*/
{ if(status(limleadingterms) >= KNOWN)
     return 1;
  if(!FRACTION(u))
     return 0;  /* assert(0) */
  if(complicated(ARG(0,u)) + complicated(ARG(1,u)) >= 5)
     return 1;
  return 0;
}

/*__________________________________________________________*/
int use_logdif(term u, term x)
/* u is a product or quotient; should du/dx be done by logarithmic
differentiation? Return 1 if yes, 0 if no. */
{ unsigned f = FUNCTOR(u);
  term v;
  int count;
  unsigned n,i;
  assert(f == '/' || f == '*');
  if(f == '/')
     { if(!depends(ARG(0,u),x))
          return 0;
       if(!depends(ARG(1,u),x))
          return 0;
       if(FUNCTOR(ARG(0,u)) == '*' && use_logdif(ARG(0,u),x))
          return 1;
       if(FUNCTOR(ARG(1,u)) == '*' && use_logdif(ARG(1,u),x))
          return 1;
       /* example that gets here:  (x-1)^2 (x-2)^3/(x-3)^4   */
       return 0;
     }
  /* Now f == '*' */
  count = 0;
  n = ARITY(u);
  if(n ==2 && get_currenttopic() != _logarithmic_differentiation)
     return 0;    /* Example: on x^e e^-x don't use it */
  for(i=0;i<n;i++)
     { v = ARG(i,u);
       if(depends(v,x) && (contains(v,'^') || contains(v,SQRT) || contains(v,ROOT)))
          ++count;
     }
  if(count >= 2)
     return 1;
  return 0;
}

/*______________________________________________________________________*/
static int binary_quadratic(term u, term x, term *a, term *b)
/* return 1 if u has the form a  \pm  bx^2 (where b is allowed to be
negative or a fraction, and u =   \pm  dx^2/c counts with b = d/c).
There can be more than one term 'a' which doesn't contain x.
Return 0 if u does not have this form.
If *a and *b are not ILLEGAL at input, then ONLY those values
of a and b are allowed, not different ones.  If *a and *b are
ILLEGAL at input, any values are allowed:
instantiate *a and *b to the coefficients in a + bx^2; but
*a cannot be zero (that is, there must actually be a term in x).
*/
{ int count = 0;
  int i,flag;
  term v,s,c;
  if(FUNCTOR(u) != '+')
     return 0;
  for(i=0;i<ARITY(u);i++)
     { if(contains(ARG(i,u),FUNCTOR(x)))
          { ++count;
            flag = i;
          }
      }
  if(count != 1)
     return 0;
  /* Now there's exactly one nonconstant term */
  if(FUNCTOR(*a) != ILLEGAL && !equals(ARG(i ? 0 : 1,u),*a))
     return 0;  /* fail, coefficients don't match */
  else
     *a = ARG( flag ? 0 : 1,  u);  /* instantiate *a */
  v = ARG(flag,u);
  if(NEGATIVE(v))
     v = ARG(0,v);
  twoparts(v,x,&c,&s);
  if(FUNCTOR(s) != '^' || !equals(ARG(1,s),two) || !equals(ARG(0,s),x))
     return 0;
  if(FUNCTOR(*b) != ILLEGAL && !equals(c,*b))
     return 0;  /* fail, coefficients don't match */
  *b = c;    /* instantiate *b */
  return 1;
}
/*______________________________________________________________________*/
static int pt_aux(term t, term x, term *a, term *b)
/* return 2 or more if t contains a subterm or subterms
sqrt( \pm a \pm x^2), or ( \pm a \pm x^2)^( \pm n/2), or with bx^2/c instead of x^2,
and is otherwise is a rational function in x.  The return value
is 1 + the number of such subterms.  If there are several such
subterms they must be identical, i.e. the same coefficients.
Return 1 if it is a rational function.
Return 0 otherwise.
*/
{ unsigned f = FUNCTOR(t);
  unsigned i,n = ARITY(t);
  int err,ans;
  term u;
  if(f == '-')
     return pt_aux(ARG(0,t),x,a,b);
  if(f == SQRT ||
     (f == '^' && FRACTION(ARG(1,t)) && equals(ARG(1,ARG(1,t)),two))
    )
     { u = ARG(0,t);
       if(binary_quadratic(u,x,a,b))
          return 2;
       return 0;
     }
  if(ATOMIC(t))
     return 1;
  if(f == '^' && isinteger(ARG(1,t)))
     return pt_aux(ARG(0,t),x,a,b);
  if(f != '*' && f != '+' && f != '/')
     return contains(t,FUNCTOR(x)) ? 0 : 1;
  ans = 1;
  for(i=0; i<n; i++)
     { err = pt_aux(ARG(i,t),x,a,b);
       if(err == 0)
          return 0;
       ans += (err-1);
     }
  return ans;
}

/*______________________________________________________________________*/
int use_trigsubtan(term t,term x)
/* t is an integrand, x the variable of integration.
Return 1 in certain special cases where x = tan \theta should
be used, namely when  t = 1/(r+cx^2)^n  don't forget negative
exponents, and half-integer exponents.
*/
{ term u,v,base,power,c,s;
  if(FUNCTOR(t) == '^' && NEGATIVE(ARG(1,t)))
     { base = ARG(0,t);
       power = ARG(0,ARG(1,t));
     }
  else if(FRACTION(t) && ONE(ARG(0,t)) && FUNCTOR(ARG(1,t)) == '^')
     { base = ARG(0,ARG(1,t));
       power = ARG(1,ARG(1,t));
     }
  else
     return 0;
  if(FUNCTOR(base) != '+' || ARITY(base) != 2)
     return 0;
  if(!isinteger(power) && !(RATIONALP(power) && equals(ARG(1,power),two)))
     return 0;
  if(contains(ARG(0,base), FUNCTOR(x)))
     { v = ARG(1,base);
       u = ARG(0,base);
     }
  else
     { u = ARG(1,base);
       v = ARG(0,base);
     }
  if(contains(v,FUNCTOR(x)))
     return 0;
  if(NEGATIVE(v))
     return 0;
  twoparts(u,x,&c,&s);
  if(FUNCTOR(s) != '^' || !equals(ARG(1,s),two))
     return 0;
  return 1;
}

/*______________________________________________________________________*/
int use_trigsubsec(term t,term x)
/* t is an integrand, x the variable of integration.
Return 1 in certain special cases where x = sec \theta should
be used, namely when  t = 1/(cx^2-r)^n ; don't forget negative
exponents, and half-integer exponents.
*/
{ term u,v,base,power,c,s;
  if(FUNCTOR(t) == '^' && NEGATIVE(ARG(1,t)))
     { base = ARG(0,t);
       power = ARG(0,ARG(1,t));
     }
  else if(FRACTION(t) && ONE(ARG(0,t)) && FUNCTOR(ARG(1,t)) == '^')
     { base = ARG(0,ARG(1,t));
       power = ARG(1,ARG(1,t));
     }
  else
     return 0;
  if(FUNCTOR(base) != '+' || ARITY(base) != 2)
     return 0;
  if(!isinteger(power) && !(RATIONALP(power) && equals(ARG(1,power),two)))
     return 0;
  if(contains(ARG(0,base), FUNCTOR(x)))
     { v = ARG(1,base);
       u = ARG(0,base);
     }
  else
     { u = ARG(1,base);
       v = ARG(0,base);
     }
  if(contains(v,FUNCTOR(x)))
     return 0;
  if(!NEGATIVE(v))
     return 0;
  twoparts(u,x,&c,&s);
  if(FUNCTOR(s) != '^' || !equals(ARG(1,s),two))
     return 0;
  return 1;
}

/*______________________________________________________________________*/
int possible_trigsub(term t, term x)
/* return 1 or more if t is a rational function except for some subterms
sqrt( \pm a \pm x^2), or ( \pm a \pm x^2)^( \pm n/2), or the above with bx^2/c instead of x^2.
Such a term must actually occur if 1 is returned.  The return value is
the number of such subterms.
   However, reject a few cases which are better done by
ordinary substitution, namely  x f(x) and x/f(x) where
f is a square root or power of a term a+bx^2.
*/
{ unsigned f = FUNCTOR(t);
  term u,v;
  int ans;
  term a,b;
  SETFUNCTOR(a,ILLEGAL,0);
  SETFUNCTOR(b,ILLEGAL,0);
  if( (f == '*' || f == '/') &&
      ARITY(t) == 2 &&
      equals(ARG(0,t),x)
    )
     { u = ARG(1,t);
       if(FUNCTOR(u) == SQRT ||
          (FUNCTOR(u) == '^' && FRACTION(ARG(1,u)) && equals(ARG(1,ARG(1,u)),two))
         )
          { v = ARG(0,u);
            if(binary_quadratic(v,x,&a,&b))
               return 0;  /* intsub will work better */
          }
     }
  ans = pt_aux(t,x,&a,&b);
  if(!ans)
     return 0;
  return ans-1;
}
/*______________________________________________________________________*/
int ftrig(term t, term x)
/* return nonzero if t is a function of trig functions of x
   (If it is, the Weierstrass substitution can be used.)
   Return value 1 means t is constant, 2 means it actually
   contains a trig function of x, 0 means it contains x in
   some other context.
*/
{ unsigned i,n;
  int ans,k;
  unsigned f = FUNCTOR(t);
  if(ISATOM(t))
     return equals(t,x) ? 0 : 1;
  if(OBJECT(t))
     return 1;
  n = ARITY(t);
  if(n == 1 && TRIGFUNCTOR(f) && equals(ARG(0,t),x))
     return 2;
  ans = ftrig(ARG(0,t),x);
  if(ans == 0)
     return 0;
  for(i=1;i<n;i++)
     { k = ftrig(ARG(i,t),x);
       if(k==0)
          return 0;
       if(k==2)
          ans = 2;
     }
  return ans;
}
/*______________________________________________________________*/
int is_sincos(term t, term x)
/* return 1 if t = sin x + cos x;
   return -1 if t = sin x - cos x or cos x - sin x;
   return 0 otherwise.
*/
{ term p,q;
  unsigned f,g;
  int sign = 1;
  if(FUNCTOR(t) != '+')
     return 0;
  if(ARITY(t) != 2)
     return 0;
  p = ARG(0,t);
  q = ARG(1,t);
  if(ATOMIC(p) || ATOMIC(q))
     return 0;
  if(NEGATIVE(p) && NEGATIVE(q))
     return 0;
  if(NEGATIVE(p))
     { sign = -1;
       p = ARG(0,p);
     }
  if(NEGATIVE(q))
     { sign = -1;
       q = ARG(0,q);
     }
  if(ARITY(p) != 1 || ARITY(q) != 1)
     return 0;
  if(!equals(ARG(0,p),x) || !equals(ARG(0,q),x))
     return 0;
  f = FUNCTOR(p);
  g = FUNCTOR(q);
  if(f == SIN && g == COS)
     return sign;
  if(f == COS && g == SIN)
     return sign;
  return 0;
}
/*_________________________________________________________________________*/
static int evil_roots(term t,term x)
/* return 1 if t is a root or sqrt containing x, or is a product or sum containing
a factor or summand with evil roots. */
{ unsigned short n,f;
  int i;
  if(NEGATIVE(t))
     t = ARG(0,t);
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if(f == ROOT || f == SQRT)
     return contains(t,FUNCTOR(x));
  if(f != '*')
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(evil_roots(ARG(i,t),x))
          return 1;
     }
  return 0;
}
/*_________________________________________________________________________*/
static int contains_log2(term t)
/* return 1 if t is a product containing a log or power of a log term as a factor */
{ unsigned short i,n,f;
  if(FUNCTOR(t) != '*')
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { f = FUNCTOR(ARG(i,t));
       if(f == '^')
          f = FUNCTOR(ARG(0,ARG(i,t)));
       if(f == LN || f == LOG  || f == LOGB)
          return 1;
     }
  return 0;
}
/*_________________________________________________________________________*/
int stop_lhopital(term t)
/* t is a limit term.  Return 1 if L'Hospital's rule should NOT be used
on t.  Return 0 if it should be tried. */
{ term x,u,num,denom;
  if(get_problemtype() == DIFFERENTIATE_FROM_DEFN)
     return 1; /* NEVER use lhopital under DIFFERENTIATE_FROM_DEFN */
  if(FUNCTOR(t) != LIMIT)
     return 1;  /* assert(0) */
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  /* t is lim(x->a,u) or lim(x->a,dir,u) */
  if(!FRACTION(u))
     return 1;   /* this includes x - sqrt(x^2+x) */
  num = ARG(0,u);
  denom = ARG(1,u);
  if(lhopital_certain(num,denom,x))
     return 0;   // it will work!   
  /* check for the case  (a sqrt b)/(c sqrt d) where both b and d
     contain x.  This just reduces to another limit of the same form,
     equally indeterminate.  The same with roots in place of sqrts. */
  if(evil_roots(denom,x) &&
     (evil_roots(num,x) || !contains(num,LN))
    )
     return 1;
  /* This used to read (evil_roots(num,x) && evil_roots(denom,x)).
     But consider for example x+sqrt(x^2+x) in the denom.
     the denom; this goes nowhere.  Perhaps evil_roots(denom) would be
     best, but the code above allows for the possibility of differentiating
     away a log in the numerator.
   */
  if(contains_fractional_exponents(t))
     return 1;
  if(contains_sqrt(t))
     return 1;
  /* |x|^c/x */
  if(equals(denom,x) &&
     FUNCTOR(num) == '^' &&
     FUNCTOR(ARG(0,num)) == ABSFUNCTOR &&
     equals(ARG(0,ARG(0,num)),x)
    )
     return 1;
  /* (e^(u ln v))/x  */
  /* This becomes e^(u ln v)/v times  (v'u + u'v ln v) and if the
     latter is nonzero it gets pulled out and a loop is created. */
  if(equals(denom,x) &&
     FUNCTOR(num) == '^' &&
     contains_at_toplevel(ARG(1,num),LN)
    )
     return 1;

  /* Examples:  3^(x-1)/5^x  or x 3^(x-1)/5^x lead to an infinite regress */
  /* But (e^x + x)/e^x works fine by L'Hopital, so don't overdo it. */

  if(
     (FUNCTOR(num) == '*' || FUNCTOR(num) == '^') &&
     (FUNCTOR(denom) == '*' || FUNCTOR(denom) == '^') &&
     contains_in_exponent(num,FUNCTOR(x)) &&
     contains_in_exponent(denom,FUNCTOR(x))
    )
     return 1;
  /* Next, stop lhopital on things like  n^2 ln n / ((n+1)^2 ln(n+1)) */
  if(FUNCTOR(num) == '*' && contains_log2(num))
     return 1;
  if(FUNCTOR(denom) == '*' && contains_log2(denom))
     return 1;
  return 0;
}

/*_______________________________________________________________*/
static int pimultiple(term a)
/* return 1 if a is an integer multiple of pi */
{ term p;
  polyval(make_fraction(a,pi_term),&p);
  return isinteger(p);
}
/*________________________________________________________________*/
static int odd_mul_piover2(term a)
/* return 1 if a is an odd multiple of pi/2 */
{ term p;
  polyval(make_fraction(product(two,a),pi_term),&p);
  return isinteger(p) && isodd(p);
}

/*________________________________________________________________*/
static int polysqrt(term t, term x)
/* return 1 if t is a sum of polynomials or sqrts or roots or fractional powers of polynomials in x */
{ unsigned short n;
  int i;
  term u;
  if(FUNCTOR(t) != '+')
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(NEGATIVE(u))
          u = ARG(0,u);
       if(FUNCTOR(u) == SQRT)
          u = ARG(0,u);
       else if(FUNCTOR(u) == ROOT && INTEGERP(ARG(0,u)))
          u = ARG(1,u);
       else if(FUNCTOR(u) == '^' && RATIONALP(ARG(1,u)))
          u = ARG(0,u);
       else if(FUNCTOR(u) == '^' && NEGATIVE(ARG(1,u)) && RATIONALP(ARG(0,ARG(1,u))))
          u = ARG(0,u);
       if(!ispolyin(u,x))
          return 0;
     }
  return 1;
}
/*____________________________________________________________________________________*/
static int contains_trigsquare(term u, term x)
/* return trig functor f  if  u contains a subterm f^{2n}(...), 
and the integral of u should be done by making a double-angle
substitution for this term.   
If such a term is the denominator of u and no such term 
occurs in the numerator, return 0;  Example,  1/sin^2 x,  which
should become csc^2 x in an integral.   
Also return 0 if u contains no trig squares. 
*/
{ int i;
  unsigned short f,n;
  term v;
  if(ATOMIC(u))
     return 0;
  if(FRACTION(u))
     { f = contains_trigsquare(ARG(0,u),x);
       if(f)
          return f;
        v = ARG(1,u);
        if(FUNCTOR(v) == '^' && ISINTEGER(ARG(1,v)) && EVEN(ARG(1,v)))
            return 0;
      }
  n = ARITY(u);
  if(FUNCTOR(u) == '^' && ISINTEGER(ARG(1,u)) && EVEN(ARG(1,u)))
     { f = FUNCTOR(ARG(0,u));
       if(TRIGFUNCTOR(f) && contains(ARG(0,u),FUNCTOR(x)))
          return f;
     }
  for(i=0;i<n;i++)
     { f = contains_trigsquare(ARG(i,u),x);
       if(f)
          return f;
     }
  return 0;
}

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