Sindbad~EG File Manager

Current Path : /usr/home/beeson/Otter-Lambda/yyy/automode/
Upload File :
Current File : /usr/home/beeson/Otter-Lambda/yyy/automode/preops.c

/* pre-associated operations in Mathpert
M. Beeson
1.7.91 Original date
6.28.99 modified
1.5.00  added code to block addfractions on complex numbers
1.13.00 modified stop_orderfactors
1.13.00 added complex_addfractions_conditions
1.13.00 added code near "secrecip"
1.18.00 modified stop_orderterms and stop_orderfactors
2.3.00 modified stop_orderterms for complex equation topics
2.3.00 added (trigexpandflag & 1)  as a condition for using the doublecos operations
2.25.00 modified exponential_factor to not count linear exponents
6.16.00 modified intsub_in_preops
3.8.01 added common_factor and code that uses it.
3.9.01 added secsqminustansq etc.
6.22.04 don't use rootofpower etc. on complex arguments
8.27.04 added contains_big_power and code that calls it in stop_cancelgcd.
1.27.06 added sgrecip2 and sgrecip3 and modified conditions for sgfract1 and sgfract2
        changed trigargsgcd1  at the ISATOM line to return 0 instead of 1.
*/

#define AUTOMODE_DLL
#include <assert.h>
#include <string.h>
#include <math.h>     /* fabs, needed by ISZERO */
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "document.h"
#include "tdefn.h"
#include "checkarg.h" /* for operator typedef */
#include "ops.h"  /* for prototypes of operators */
#include "operator.h"
#include "trig.h"
#include "calc.h"
#include "series.h"
#include "prover.h"
#include "polynoms.h"
#include "probtype.h"
#include "exec.h"
#include "algaux.h"
#include "order.h"
#include "automode.h"
#include "eqn.h"
#include "mplimits.h"
#include "trigtran.h"
#include "symbols.h"
#include "cflags.h"   /* set_factorflags     */
#include "deriv.h"    /* derivative          */
#include "automode.h" /* select_trigeval_op  */
#include "pvalaux.h"  /* isinteger, squareofone, expandable_sum */
#include "trigpoly.h" /* trigpolyargs2       */
#include "autoeqn.h"  /* inhibit_transfer    */
#include "autosimp.h" /* get_whichpass, get_path, get_pathlength */
#include "simpsums.h" /* collect             */
#include "cancel.h"   /* cancel              */
#include "autosum.h"  /* immediate_comdenom  */
#include "autoeqn.h"  /* different_sqrts     */
#include "preprod.h"  /* special_dif_of_squares */
#include "preops.h"
#include "autotrig.h" /* set_sincosflag      */
#include "simpprod.h" /* expandable          */
#include "pda.h"      /* equal_mod_order     */
#include "deval.h"    /* seminumerical       */
#include "fremark.h"  /* contains_zero_denom */
#include "dcomplex.h" /* ceval.h needs it    */
#include "ceval.h"    /* complexnumerical    */
#include "maxsub.h"   /* maximal_sub         */
#include "scontrol.h" /* series_preops       */


static int stopcancel(term t);
static int contains_fract(term u);
static int contains_deriv(term u, term x);
static int trigfactor(term t);
static int suppress_trig_expansion(term u, term x);
static int intsub_on_sum(term, term);
static int logtrig(term);
static int bivariate(term);
static int perfect_power(long x, long n);
static int perfect_square(long);
static int blockintlinearity(term u, term x);
static int block_regroupterms(term t);
static int trignegative(term t);
static int count_abs(term t);
static int stop_cancelgcd(term t);
static int stop_differenceofsquares(term t);
static int local_contains_trig(term t);
static int commondenom_in_preops(term t);
static int stop_maxsub(term u);
static int trigproducts(term t);
static int trigargsgcd1(term t);
static int trigargsgcd(term t, term *gcd);
static unsigned short tpf_aux(term t, unsigned short a, unsigned short b);
int contains_power_of_sum(term t);
static unsigned short twologs(term t);
static int forced_logcollect(unsigned short f, term t);
static int contains_odd_power(term t, unsigned short f);
static int contains_even_power(term t, unsigned short f);
static int contains_complex_exponentials(term t);
static int stoplogofpower(term u);
static int trigalg_same(term u, term x);
static int exponential_factor(term t,term x);
static int stop_arith(term t);
static int obvious_trig(term t);
static int complex_addfractions_conditions(term t);
static int common_factor(term u, term v);
/*_____________________________________________________________________*/
static int trigpolyflag;

int get_trigpolyflag(void)
{ return trigpolyflag;
}

void set_trigpolyflag(int n)
/* used to initialize trigpolyflag in one_step. */
{ trigpolyflag = n;
}

/*_____________________________________________________________________*/
/* pre_ops and post_ops specify the details of the simplification algorithm
by telling what ops are 'pre-associated' and 'post-associated' with
each functor and its daughter functors. */

/* o is an array of operators, empty at the beginning, but
presumed to have space for at least MAXOPS operators to be
returned, and MAXOPS better be large enough to hold the largest answer.
nops will be returned as the number of operators placed into array o. */

void pre_ops(term t, actualop *o, int *nops)
{ unsigned short f = FUNCTOR(t);
  unsigned short n = ARITY(t);
  char buffer[DIMREASONBUFFER];
  static int polyvalflag;   /* set to 1 when pathlength = 0 if polyvalop is used */
  int currentline = get_currentline();
  int problemtype = get_problemtype();
  int currenttopic = get_currenttopic();
  int factorflag, logcollectflag, trigexpandflag, radicalflag;
  static int toplevel_arithmetic;
  unsigned short g,h;
  const int intflag = get_intflag();
  const int indexflag = get_indexsumflag();
  const int seriesflag = get_seriesflag();
  int statusflag,numberflag,k;
  term u,v,num,denom,x,a,b,gcd,w,q;
  aflag arithflag = get_arithflag();
  int pathlength = get_pathlength();
  unsigned short const *path = get_path();
  unsigned short tflag=0;
  unsigned short hypertflag = 0;
  int trigcount,j,i=0;
  int topflag =  (pathlength == 0 || (pathlength == 2 && path[0] == '-'));
  unsigned short localtrigflag;
  term temp;
  int changelimitvarflag = 0;
  if(problemtype == MINMAX && currentline == 0)  /* get started */
     { if(FUNCTOR(t) == '=' && constant(ARG(1,t)))
          { o[i] = functionisconstant; ++i;
          }
       o[i] = addcriticalpoints; ++i;
     }
  if(ATOMIC(t))
     { *nops = i;
       return;
     }
  factorflag = get_factorflag();
  trigexpandflag = get_trigexpandflag();
  radicalflag = get_radicalflag();
  logcollectflag = get_logcollectflag();
  if(f == DIFF)
     { if(!depends(ARG(0,t),ARG(1,t)))
          { o[i] = difconstant; ++i;
            /* before trying to simplify ARG(0,t); especially if ARG(0,t)
               is an integral! */
          }
       g = FUNCTOR(ARG(0,t));
       if(g == INTEGRAL)
          { o[i] = fundamentaltheorem2; ++i;
            /* get it in the list before polyvalop, otherwise e.g.
               a constant can be pulled out of the integral and the
               opportunity to use the fundamental theorem is missed */
          }
       if((g == SEC || g == TAN || g == CSC) &&
          ISATOM(ARG(0,ARG(0,t))) &&
          problemtype != DIFFERENTIATE_FROM_DEFN
         )
          { o[i] = g == SEC ? difsec : g == TAN ? diftan : difcsc; ++i;
          }  /* before sec goes to 1/cos, which screws up trig integrals */
     }
  if(pathlength == 0)
     toplevel_arithmetic = 0;
  if(pathlength == 0 && problemtype == TRIG_IDENTITY)
     { term *atomlist;
       int nvariables = variablesin(t,&atomlist);
       free2(atomlist);
       if(nvariables > 1)
          { o[i] = trigdoublesub; ++i;
          }
       if(nvariables)
          { if(!stop_maxsub(t))
               { o[i] = maximalsub; ++i;
               }
            if(get_whichpass() > 1 || !trigargsgcd1(t))
               /* First try to solve it without substitutions.  In some
                  cases, for example sin^4 (x/2) + cos^4(x/2) = ...,
                  a substitution u = x/2 will ruin things.  Besides, if the
                  identity can be done with half-angle operations, it's
                  somewhat more esthetic not to use a substitution.
                  But e.g. on  2 sin(x/2) cos(x/2) = sin x,  it makes
                  good sense to use u = x/2, rather than express
                  sin(x/2) as a square root and make assumptions.
                     However, an identity which involves e.g. sin (8x) and
                  trig functions of 2x, should begin by u = 2x, so in such
                  a case we do NOT want to wait till whichpass > 1.  That's
                  what trigargsgcd is for.
               */
               { set_substitutionflag(VISIBLESUBS);
                 localtrigflag = 0;
                 set_trigflag(t,&localtrigflag);
                 if(localtrigflag)
                    /* don't make substitutions in purely algebraic identities.
                       Otherwise we get several useless substitutions after the first
                       sometimes.  */
                    { o[i] = makesubstitution; ++i;
                    }
               }
          }
     }
  if(pathlength == 0 &&
     problemtype != LINEAR_EQUATION &&
     problemtype != LINEAR_EQUATIONS &&
     (
       (SOLVETYPE(problemtype) && !solved(t,get_eigenvariable())) ||
       problemtype == FACTOR ||
       problemtype == SIMPLIFY
     ) &&
     !mvpoly(t) &&
     !contains_bound_vars(t)
    )
     { if(f == OR)
          { o[i] = trueeqn; ++i;
            o[i] = spliteqn; ++i;  /* try it before maximalsub */
            o[i] = spliteqn2; ++i;
          }
       if(problemtype != IMPLICIT_DIFF &&
          f != '=' &&
          /* when solving equations it will be called in pre_equation */
          !stop_maxsub(t)
         )
          { o[i] = maximalsub; ++i;
          }
     }
  if(pathlength == 0 && CALCULUS_TOPIC(currenttopic) && currenttopic != _minmax)
     { o[i] = undefinedpart; ++i;
     }
  if(pathlength == 0 &&
     currenttopic != _evaluate_numerically &&
     currenttopic != _numerical_exponents &&
     currenttopic != _alg1_exponents &&
     currenttopic != _add_numerical_fractions &&
     currenttopic != _numerical_radicals &&
     currenttopic != _alg1_radicals
    )
     { if(INEQUALITY(f) && SOLVETYPE(problemtype) &&
          FUNCTOR(ARG(0,t)) == '^' && FUNCTOR(ARG(1,t)) == '^' &&
          equals(ARG(0,ARG(0,t)),ARG(0,ARG(1,t))) &&  /* 2^x = 2^3 for example */
          INTEGERP(ARG(0,ARG(0,t))) && INTEGERP(ARG(0,ARG(1,t))) &&
          (numerical(ARG(0,t)) || numerical(ARG(1,t)))
         )
          { if(f == '=')
               { o[i] = logbeqn; ++i;  /* don't use arithmetic */
               }
            else
               { solve_ineq(t, i,o,nops);
                 return;
               }
          }
       else if(INEQUALITY(f) && SOLVETYPE(problemtype) &&
          FUNCTOR(ARG(0,t)) == '^' && FUNCTOR(ARG(1,t)) == '^' &&
          isinteger(ARG(1,ARG(0,t))) && isinteger(ARG(1,ARG(1,t))) &&
          !polygcd(ARG(1,ARG(0,t)),ARG(1,ARG(1,t)),&gcd) && !ONE(gcd) &&
          (f == '=' || isodd(gcd) || econstant(ARG(1,t)) || econstant(ARG(0,t)))
         )
          { if(equals(gcd,two) && f == '=')
               { o[i] = sqrteqn; ++i;
               }
            else if(f == '=')
               { o[i] = rooteqn; ++i;  /* example: x^3 = 3^6; don't use arithmetic */
               }
            else
               { /* inequalities */
                 solve_ineq(t,i,o,nops);
                 return;
               }
          }
       else if(!stop_arith(t) && !contains_big_exponents(t))
          { o[i] = arithmetic; ++i;
            if(arithflag.complex)
               { o[i] = weakcomplexarithmetic; ++i;
               }
            toplevel_arithmetic = 1;
          }
     }
  if(status(polyvalop) >= KNOWN && pathlength == 0  &&
     /* pathlength == 0 ensures that this operator, which itself
        traverses the term, is not tried repeatedly on subterms */
     !(FUNCTOR(t) == INTEGRAL && (FUNCTOR(ARG(0,t)) == '*' || FRACTION(ARG(0,t)))) &&
     !(FUNCTOR(t) == INTEGRAL && NEGATIVE(ARG(0,t))) && /* use intminus instead */
     /* don't simplify an integrand e^(-t)ln(1+e^(-t))/(1+e^(-t)) because you'll
        lose the chance to find u = (1+e^(-t)) */
     !(FUNCTOR(t) == INTEGRAL && !contains(ARG(0,t),FUNCTOR(ARG(1,t)))) &&
     /* example, integral(-c,x); use intconst rather than imitating intminus
        as polyval would do. */
     !contains(t,LIMIT) && /* work on the limits first; some may be undefined.*/
     !contains_big_exponents(t) &&
     ( currenttopic != _complex_trig || !local_contains_trig(t)) &&
     /* when doing complex trig, wait to simplify until all trig functions
        have been expressed in complex form */
     ( currenttopic != _binomial_theorem || !contains_power_of_sum(t)) &&
     !SOLVETYPE(problemtype) &&  /* it's in pre_equation after substitutions */
     !obvious_trig(t) &&  /* a(cos^2 x + sin^2 x) + b should not be expanded */
     FUNCTOR(t) != SUM &&   /* don't simplify sum((a/b)^n,...) to sum(a^n/b^n) */
     !iscomplex(t)   /* don't simplify i/i^2 to 1/i; polyvalop doesn't do complex simplification */
    )
     { o[i] = polyvalop; ++i;
       polyvalflag = 1;
     }
  else if(pathlength == 0)
     { if(SOLVETYPE(problemtype) &&
          problemtype != LINEAR_EQUATION &&
          problemtype != LINEAR_EQUATIONS
         )
          polyvalflag = 1;
       else
          polyvalflag = 0;  /* so polyvalflag is reset when pathlength == 0 */
     }
  switch(f)
    { case '-' :
         g = FUNCTOR(ARG(0,t));
         if(g == '-')
            { o[i] = doubleminus; ++i;
            }
         else if(g == '+' && (pathlength < 2 || path[pathlength-2] != ROOT))
            /* root(3,-(a+b)) should become - root(3,a+b), not root(3,-a-b) */
            /* What about under an even root?  I hope it doesn't matter much,
               because from here I can't tell if the root is even or odd.  To
               fix this I would have to have another flag, oddrootflag, which
               was set and restored in autosimp as we go into and out of
               ROOT terms.  It doesn't seem worth the trouble. */
            { o[i] = pushminusin; ++i;
            }
         if(g == '/' && get_complex() &&
            (complexexpression(ARG(0,ARG(0,t))) || complexexpression(ARG(1,ARG(0,t))))
           )
            { o[i] = complexform; ++i;
              /* example, -(2+i)/2i goes to -1/2 + i */
            }
         break;
      case '+' :
         o[i] = dropzero; ++i;
         /* catch x^(2+3) so the 2+5 changes to 5 right away */
         if(pathlength >= 2 && path[pathlength-2] == '^' &&
            path[pathlength-1] == 2 && numerical(t)
           )
            { o[i] = arithmetic; ++i;
            }
         if(CALCULUS_TOPIC(currenttopic) && contains(t,INFINITY))
            { o[i] = infinityplusinfinity; ++i;
              o[i] = infinityminusinfinity; ++i;
            }
         if(pathlength == 2 && path[0] == '=' && currenttopic != _complete_the_square)
            { /* see if the other side of the equation is zero */
              q = history(get_activeline());
              if(FUNCTOR(q) == '=' && ZERO(ARG(path[1]==1 ? 1 : 0, q)))
                 { o[i] = contentfactor; ++i;
                   /* example:  sin x cos x + sin^2 x = 0.
                      If we don't factor it now, sin^2 will become 1-cos^2
                      before we get to autosum, and we can't solve it. */
                 }
              /* Example:  sin x cos x + 1-cos^2 x.
                 We need to apply 1-cos^2 x = sin^2 x.  This should
                 ONLY be done if the result is going to factor,
                 otherwise we risk an infinite regress changing
                 cos^2 to sin^2 and vice-versa. */
              if(!sinsquare2(t,zero,&w,buffer) && !content_factor(w,&a,&b))
                 { o[i] = sinsquare2; ++i;
                 }
              if(!sinsquare3(t,zero,&w,buffer) && !content_factor(w,&a,&b))
                 { o[i] = sinsquare3; ++i;
                 }
            }
         if(pathlength == 4 && path[0] == OR && path[2] == '=')
            { q = history(get_activeline());
              if(FUNCTOR(q) == OR)
                 { q = ARG(path[1]-1,q);
                   if(FUNCTOR(q) == '=' && ZERO(ARG(path[3]==1 ? 1 : 0,q)))
                      { o[i] = contentfactor; ++i;
                      }
                   if(!sinsquare2(q,zero,&w,buffer) && !content_factor(w,&a,&b))
                      { o[i] = sinsquare2; ++i;
                      }
                   if(!sinsquare3(q,zero,&w,buffer) && !content_factor(w,&a,&b))
                      { o[i] = sinsquare3; ++i;
                      }
                 }
            }
         if(almost_algebraic(t) && !iscomplex(t))
            /* example,  (x - 1/2 - sqrt(17)/2) */
            { o[i] = polyvalop; ++i;
            }
         if(get_complex() && status(polyvalop) >= KNOWN && !complexexpression(t) && mvpoly2(t))
            { o[i] = polyvalop; ++i;
              /* simplify polynomials in i, e.g. under SQRT */
              /* but don't simplify expressions already of the form u + vi */
            }
         if(commondenom_in_preops(t))
            { if(status(commondenomandsimp)>= KNOWN)
                 { o[i] = commondenomandsimp; ++i;
                 }
              else
                 { o[i] = commondenom; ++i;
                 }
            }
         if(!seminumerical(t) &&  /* don't factor algebraic numbers */
            (currenttopic == _factor_by_grouping ||
             currenttopic == _advanced_factoring ||
             currenttopic == _cubic_one_root ||
             currenttopic == _complex_cubics
            ) &&
            ( !get_complex() || !contains_complex_exponentials(t))
           )
            { if(ARITY(t) == 3)
                 { o[i] = factorbygrouping; ++i;
                   /* Must come before regroupterms.
                      Example:  h^2k^2 + 4k^2 + (h^2k + 4k)
                      For arities 4 to 6 it's in autosum.c
                   */
                 }
              if(ARITY(t) == 2 && FUNCTOR(ARG(0,t)) == '*' && FUNCTOR(ARG(1,t)) == '*')
                 /* a(b-c) + d(c-b) = a(b-c) - d(b-c) */
                 { o[i] = pullminusout2; ++i;
                 }
              o[i] = contentfactor; ++i;
              /* try it before regroupterms.
                 Example:  2a(a+3)-(3+a)
                 But for arity 3 it should come AFTER factorbygrouping.
                 Example: k^2(h^2 + 4) + h^2k + 4k,
                 we don't want to factor k out of the whole
                 sum but rather factor k out of the second two terms.
              */
            }
         if(!polyvalflag)
            /* so polyvalop hasn't been thrown in when pathlength == 0 */
            { /* regroupterms will do the work of pushminusin,
                 which we want to prevent when regroupterms is only
                 LEARNING.  We have regroupterms in pre_ops because
                 it must come before additivecancel, which also
                 will regroup terms (looking strange); so now we
                 must check that there are no negative sums
                 within the terms to be regrouped. */
              if(status(regroupterms) > LEARNING || !block_regroupterms(t))
                 { /* no negative sums, go ahead and regroup */

                   o[i] = regroupterms; ++i;
                   o[i] = additivecancel; ++i;
                   /* additivecancel should precede factoring, so as not to
                      factor x^2-x^2  for example */
                 }
            }

         /* factoring by pattern-matching comes in pre_ops, so that we
            don't miss obvious cases by doing simple things first,
            as in 2^3 - (3b)^3  for example.   The factoring operations
            are listed in factorops in factor.c and the list there must
            match the total of operations given in pre_ops and autosum.
         */

         if(!constant(t))
            { tflag = hypertflag = 0;
              if(pathlength <= 2 && path[0] == '=')
                 { set_trigflag(history(currentline),&tflag);
                   /* this takes both sides of the equation into account,
                      which is necessary to prevent one side of an
                      identity being written as a polynomial in sin x
                      while the other side gets written as a polynomial
                      in cos x, so the identity can't be verified.
                      It's probably a good thing when solving equations, too.
                   */
                   set_hypertrigflag(history(currentline),&hypertflag);
                 }
              else
                 { set_trigflag(t,&tflag);
                   set_hypertrigflag(t,&hypertflag);
                 }
              trigcount = tflag ? nbits(tflag) : 0;
              if(INDICATES(tflag,SEC) && INDICATES(tflag,TAN))
                 { /* example,  sec^2 x - tan^2 x = 1.  If we don't change the 
                      left side to 1 in pre_ops, it will get factored. */
                   o[i] = secsqminustansq; ++i;
                   o[i] = tansquare2; ++i;
                   o[i] = secsqtotansq; ++i;
                 }
              if(INDICATES(tflag,SIN) && INDICATES(tflag,COS))
                 { o[i] = sinsquare1; ++i; /* sin^2 + cos^2 = 1 */
                   /* sinsquare1 must be applied in preops because in case
                      sin^2 2x + cos^2 2x + sin x
                      it will start using double angle formulas before postops gets the sum.
                      Also in integral(sin^2x + cos^2 x,x): if sinsquare1 is not
                      in preops, half-angle formulas will be used instead.
                   */
                   /* Next catch expanded powers of sin^2 + cos^2, because
                      it looks silly to fail to factor such a thing and
                      make it 1, e.g. if such a thing is the integrand we
                      then do a long useless trig computation!
                   */
                   if(ARITY(t) == 2)
                      { /* check for sin (x-a) cos(x+a) + cos(x-a) sin(x+a) etc. */
                        int k = trigproducts(t);
                        switch(k)
                           { case 0:
                                break;
                             case 1:
                                o[i] = sinsumrev; ++i;
                                break;
                             case 2:
                                o[i] = sindifrev; ++i;
                                break;
                             case 3:
                                o[i] = cossumrev; ++i;
                                break;
                             case 4:
                                o[i] = cosdifrev; ++i;
                                break;
                           }
                      }
                   if(ARITY(t) == 3 && squareofone(t))
                      { o[i] = factorsquareofsum; ++i;
                      }
                   if(ARITY(t) > 3 && powerofone(t))
                      { switch(ARITY(t))
                           { case 4:
                                o[i] = factorcubeofsum; ++i;
                                break;
                             case 5:
                                o[i] = factor4thofsum; ++i;
                                break;
                             default:
                                o[i] = factornthofsum; ++i;
                           }
                      }
                 }
              if(hypertflag &&
                 currenttopic != _hyperfunctions &&
                 hyperindicates(hypertflag,COSH) &&
                 hyperindicates(hypertflag,SINH)
                )
                 { o[i] = coshsqminussinhsq; ++i;
                   if(get_hflag() || get_whichpass() > 1)
                      /* hflag nonzero means the problem already contains
                         exponentials.  These operations introduce exponentials
                         and so can screw up hyper-trig identities that otherwise
                         can be proved without introducing exponentials.
                      */
                      { o[i] = coshplussinh; ++i;
                        o[i] = coshminussinh; ++i;
                      }
                 }
              if(hypertflag &&
                 currenttopic != _hyperfunctions &&
                 hyperindicates(hypertflag,COSH)
                )
                 { o[i] = coshsqminus1; ++i;
                 }
              if(hypertflag &&
                 currenttopic != _hyperfunctions &&
                 hyperindicates(hypertflag,SINH)
                )
                 { o[i] = sinhsqplus1; ++i;
                 }
              if(hypertflag &&
                 currenttopic != _hyperfunctions &&
                 hyperindicates(hypertflag,TANH)
                )
                 { o[i] = oneminustanhsq; ++i;
                 }
              if(hypertflag &&
                 currenttopic != _hyperfunctions &&
                 hyperindicates(hypertflag,SECH)
                )
                 { o[i] = oneminussechsq; ++i;
                 }
            }
         if(pathlength >= 2 && path[pathlength-2] == '^' &&
            n == 2 && iscomplex(ARG(1,t)) &&
            contains(ARG(0,t),COS) && contains(ARG(1,t),SIN)
           )
            { o[i] = rectangulartopolar; ++i;
              /* example: cos(pi/4) + i sin(pi/4); this must be
                 in pre_ops or else cos(pi/4) gets evaluated
                 before we convert to polar form, resulting in
                 an ugly arctan computation when we do get to
                 polar form.  */
            }
         if(n == 2 &&
            (SIGNEDFRACTION(ARG(0,t)) || SIGNEDFRACTION(ARG(1,t))) &&
            complexnumerical(t) &&
            (contains(t,SQRT) || contains(t,ROOT)) &&
            currenttopic != _add_numerical_fractions &&
            !contains(t,'^') && /* don't work on 2^(1/2)/3^(1/2) + sqrt 4 to
                                 simplify the sqrt(4) */
            !iscomplex(t)
           )
            { o[i] = polyvalop; ++i;
              /* simplify 1/2 + sqrt(5)/2 before commondenom gets it.
                 This will get surdsimp used. */
            }
         if(inhibited(alltoleft)  /* set by completethesquare */
            ||
            (
             (FACTORFLAG ||
              (problemtype == TRIG_IDENTITY && pathlength == 2 &&
               common_variables(ARG(0,t),ARG(1,t))
               /* This clause should not cause factoring of
                  sin^t x - sin^2 y, or even x^2 - y^2;  this clause
                  is needed for more complicated situations */
              )

             ) &&
             /* allow factoring at toplevel when solving identities. */
             !constant(t) &&
             (!get_infractionflag() || !contains_fract(t)) &&
               /* don't factor (1- y^2/x^2) in the num or denom of a fraction,
                  instead wait for it to be put over a common denom */
             !suppress_factoring(problemtype,0) &&
             !(SOLVETYPE(problemtype) && count_abs(t) >= 2) &&
             !(trigcount && trig_suppress_factoring(trigcount,t))
               /* trig functions with different non-constant args?
                  or more than one trig function but all to even powers?
                  if so don't factor.  */
            )
           )
            /* don't !irreducible(t) as it probably takes
               longer than trying these simple operators */

            { if(n==2 && !insqrtflag && !inrootflag && !infractexpflag)
              /* don't factor in �(x^2-a^2), because it
                 blocks finding substitutions you need
                 to solve some equations */
                  { int j,flag=0,signflag=0,oneflag=0;
                    term trigarg;
                    unsigned short g;
                    /* 1-sin^2 = cos^2 must be tried before factoring */
                    /* and also two similar csc identities */

                    for(j=0;j<n;j++)
                       { u = ARG(j,t);
                         if(NEGATIVE(u))
                            { ++signflag;
                              u = ARG(0,u);
                            }
                         if(ONE(u))
                            { ++oneflag;
                              continue;
                            }
                         if(FUNCTOR(u) == '^' && equals(ARG(1,u),two))
                            { g = FUNCTOR(ARG(0,u));
                              if(g==SIN || g==COS ||  g==TAN || g==COT || g==CSC || g==SEC)
                                 { if(!flag)
                                      { ++flag;
                                        trigarg = ARG(0,ARG(0,u));
                                      }
                                   else if(flag && equals(ARG(0,ARG(0,u)),trigarg))
                                      ++flag;
                                 }
                            }
                       }
                    if(flag==1 && oneflag==1)
                       { if(g==SIN)
                            { if(get_trigpolyflag() != COS)
                                 { o[i] = sinsquare2; ++i;
                                 }
                            }
                         else if(g==COS)
                            { if(get_trigpolyflag() != SIN)
                                 { o[i] = sinsquare3; ++i;
                                 }
                            }
                         else if(g == CSC)
                            { if(get_trigpolyflag() != COT)
                                 { o[i] = cotsquare2; ++i;
                                 }
                            }
                       }
                    if(flag == 2 && signflag == 1 &&
                       (g == CSC || g == COT)
                      )
                       { o[i] = cscsqminuscotsq; ++i;
                       }
                    if(flag == 2 && signflag == 1 &&
                       ( g == SIN || g == COS) &&
                       get_trigpolyflag() != COS
                      )
                        { o[i] = sinsqtocossq; ++i;
                        }
                    if(!stop_differenceofsquares(t))
                       { o[i] = differenceofsquares; ++i;
                       }
                    if(get_complex() && SOLVETYPE(problemtype))
                       /* don't use this in num and denom of fractions
                          when simplifying */
                       { o[i] = sumofsquares; ++i;
                       }
                    if(!flag)  /* no exponents of two */
                       { term a = ARG(0,t);
                         term b = ARG(1,t);
                         if(NEGATIVE(a))
                            a = ARG(0,a);
                         if(NEGATIVE(b))
                            b = ARG(0,b);
                        /* We block factoring on the very special case
                           (p+q)^3 + (p-q)^3, which is better handled by
                           direct binomial expansion.
                        */
                         if( ! (
                                 FUNCTOR(a) == '^' && FUNCTOR(ARG(0,a)) == '+' && equals(ARG(1,a),three) &&
                                 FUNCTOR(b) == '^' && FUNCTOR(ARG(0,b)) == '+' && equals(ARG(1,b),three) &&
                                 ARITY(ARG(0,a)) == 2 && ARITY(ARG(0,b)) == 2 &&
                                 equals(ARG(0,ARG(0,a)),ARG(0,ARG(0,b))) &&
                                 (
                                   ( NEGATIVE(ARG(1,ARG(0,b))) && equals(ARG(1,ARG(0,a)),ARG(0,ARG(1,ARG(0,b))))) ||
                                   ( NEGATIVE(ARG(1,ARG(0,a))) && equals(ARG(1,ARG(0,b)),ARG(0,ARG(1,ARG(0,a)))))
                                 )
                               )
                           )
                            { o[i] = differenceofcubes; ++i;
                              o[i] = sumofcubes; ++i;
                              o[i] = sumoffourthpowers; ++i;
                            }
                       }
                  }
              else if(n==3 ||
                      (n==6 && bivariate(t)) ||
                      /* n==6 because of x^2+2xy+y^2+3x+3y+2  */
                      /* ok to use these under sqrt         */
                      (n==4 && bivariate(t))
                      /*n==4 because of x^2+2x+1 - y^2      */
                     )
                  {
                    o[i] = factorsquareofsum; ++i;
                    o[i] = factorsquareofdif; ++i;
                  }

                 /* You can't restrict the arity on factorquadratic to 3
                    because the constant term could be a sum; but
                    you shouldn't use it on arity 2, although it
                    gives correct output, doing so makes Mathpert
                    suggest its use as a hint instead of
                    contentfactor */

              if(n > 2 &&
                 currenttopic != _quadratic_formula &&
                 currenttopic != _complete_the_square &&
                 ( (!intflag && !indexflag && !seriesflag) || (!inrootflag && !insqrtflag && !infractexpflag))
                )
                 /* Don't factor quadratics under a root or sqrt or fractexp
                    inside an integral or indexed sum, because (in integrals) it
                    blocks completethesquare, which is necessary, and (in sums)
                    it's useless anyway. */
                 { o[i] = factorquadratic; ++i;
                   /* factorquartic is in postops so it won't be
                      used on x^4 - 2x^2y^2 + y^4  */
                 }
              switch(n)
                 { case 2:
                   case 3:
                      break;
                   case 4:
                      o[i] = factorcubeofsum; ++i;
                      break;
                   case 5:
                      o[i] = factor4thofsum; ++i;
                      break;
                   default:
                      o[i] = factornthofsum; ++i;
                      break;
                 }
              if(n==4 &&
                 SOLVETYPE(problemtype) &&
                 stricttrigpoly(t,get_eigenvariable())
                )
                /* example: 2 sin x tan x + tan x - 2 sin x -1 = 0 */
                 { o[i] = factorbygrouping; ++i;
                 }
              if(n==4 && get_nvariables() > 1)
                 { o[i] = factorhelper; ++i;
                 }
            }
         if(!toplevel_arithmetic && !contains_big_exponents(t))
                /* so arithmetic hasn't been thrown in above */
            { if(arithflag.negexp)
                 { o[i] = arithmetic; ++i;
                 }
              else  /* don't do too much arithmetic!              */
                    /* we hit this under topic _radicals          */
                    /* for example don't evaluate powers in a sum */
                    /* but DO work on 1 + 2 + �3                  */
                 { numberflag = 0;
                   for(j=0;j<n;j++)
                      { u = ARG(j,t);
                        if(NUMBER(u))
                           ++numberflag;
                      }
                   if(numberflag > 1)
                      { o[i] = arithmetic; ++i;
                      }
                 }
            }
         if(arithflag.complex)
            { o[i] = weakcomplexarithmetic; ++i;
            }

         /* use cos^2-1 => sin^2  and csc^2-1 => cot^2 and
            secsqtotansq  when not
            in fractions, when these expressions stand alone;
            otherwise, we'll get  sin^2 = 1-cos^2 => sin^2 = 1-(1-sin^2)
            when post_ops hits the cos^2. But don't do this in a
            fraction as you may need to factor and cancel. And
            don't do it if the whole currentline contains only
            one trig function. */

         if(!get_infractionflag() && ARITY(t)==2 && ONE(ARG(0,t)) &&
            NEGATIVE(ARG(1,t)) &&
            FUNCTOR(ARG(0,ARG(1,t))) == '^' &&
            equals(ARG(1,ARG(0,ARG(1,t))),two)
           )
             { unsigned short h = FUNCTOR(ARG(0,ARG(0,ARG(1,t))));
               switch (h)
                  { case COS:
                       if(
                          !((trigexpandflag & (1<<12)) && !INDICATES(tflag,SIN))
                         )
                          /* Not the case that (only sin and cos occur and sin
                             does not occur), meaning it's not the case that
                             everything is already expressed in terms of cos */

                          { o[i] = sinsquare3; ++i;
                          }
                       break;
                    case CSC:
                       o[i] = cotsquare2; ++i;
                       break;
                    case SEC:
                       o[i] = tansquare2; ++i;
                       break;
                  }
             }
         if(!get_infractionflag() && ARITY(t)==2 && equals(ARG(1,t),minusone) &&
            FUNCTOR(ARG(0,t)) == '^' && equals(ARG(1,ARG(0,t)),two)
           )
             { unsigned short h = FUNCTOR(ARG(0,ARG(0,t)));
               switch (h)
                  { case COS:
                       o[i] = sinsquare3; ++i;
                       break;
                    case CSC:
                       o[i] = cotsquare2; ++i;
                       break;
                    case SEC:
                       o[i] = tansquare2; ++i;
                       break;
                  }
             }

         /* The following operators make e.g. sin 3x + sin 5x into
         a product of trig functions.  When should they be used?
         The conditions are complicated and part of the problem
         is to decide, in the case of a sum of arity 3, which
         two args it should be applied to.  This decision must be
         made by the operators themselves.  Function trigfactor()
         in this file checks some necessary conditions.
            The operators themselves fail in auto mode if they would
         create fractional args, unless we're solving equations or
         inequalities. For example, sin(2x) - sin x  would create
         a term in sin(3x/2), which we don't want when solving
         identities, but DO want when solving equations, e.g.
         sin(3x)-sin(2x)=0 goes much easier if we use difofsin.
         */

         if( (trigexpandflag & 1) &&  /* not all trig functions have same arg */
             !limitflag && !intflag && !indexflag && !seriesflag && !difflag &&
             (ARITY(t) == 2 || ARITY(t) == 3) &&
             currenttopic != _trig_product
             /* on this topic, the point is to create sums of trig functions,
                and using sumofsin etc. creates loops. */
           )
            { j = trigfactor(t);
              if( currenttopic == _trig_factor ||
                   /* sin alpha + sin beta  and so on occur in the
                      problem sets under that topic and trigfactor
                      won't suggest using sumofsin, but on this topic
                      it should always be used. */
                  (j > 0 && ARITY(t) == 3)
                )
                 { o[i] = sumofsin; ++i;
                   o[i] = difofsin; ++i;
                   o[i] = sumofcos; ++i;
                   o[i] = difofcos; ++i;
                 }
              else if(j && ARITY(t) == 2)
                 { switch(j)
                      { case 1:
                           o[i] = sumofsin; ++i;
                           break;
                        case 2:
                           o[i] = difofsin; ++i;
                           break;
                        case 3:
                           o[i] = sumofcos; ++i;
                           break;
                        case 4:
                           o[i] = difofcos; ++i;
                           break;
                      }
                 }
            }
         if(INDICATES(tflag,COS) &&
            !indexflag &&
            !seriesflag &&
            !intflag  &&  /* don't change cos 2t to anything involving sin^2 or cos^2
                          inside an integral. In fact we do the opposite to solve
                          trig power integrals, so this would cause a loop. */
            ((tflag & 0x1000) || currenttopic == _double_angle) &&
            (trigexpandflag & 1) &&   /* not all trig functions have same arg */
            currenttopic != _trig_product && /* leave cos(2t) alone then */
            !trignegative(t)  /* don't touch cos(-2x) - cos(2x) for example
                                    because the cos(-2x) will be worked on soon */
           )
            { /* Be careful about which double cosine rule to apply.  Is there
                 a sin term already in this sum? */
              long oneflag=0, cosflag=0;
              if(INDICATES(tflag,SIN) &&
                 (problemtype != TRIG_IDENTITY || get_trigpolyflag() != SIN)
                )
                 { o[i] = doublecos6; ++i;  /* cos 2� - 1 = - 2 sin^2 � */
                 }
              /* Is there a 1 in this sum with the same sign as the cosine term ? */
              for(j=0;j<ARITY(t);j++)
                 { u = ARG(j,t);
                   if(ISINTEGER(u))
                      oneflag = INTDATA(u);
                   if(NEGATIVE(u) && ONE(ARG(0,u)))
                      oneflag = -INTDATA(u);
                   if(FUNCTOR(u) == COS && FUNCTOR(ARG(0,u)) =='*' && iseven(ARG(0,u)))
                      cosflag = 1;
                   if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == COS &&
                      FUNCTOR(ARG(0,ARG(0,u))) == '*' && iseven(ARG(0,ARG(0,u)))
                     )
                      cosflag = -1;
                   /* what about 2 - 2 cos 2x */
                   if(FUNCTOR(u) == '*' && ISINTEGER(ARG(0,u)) &&
                      FUNCTOR(ARG(1,u)) == COS &&
                      FUNCTOR(ARG(0,ARG(1,u))) == '*' &&
                      iseven(ARG(0,ARG(1,u)))
                     )
                      cosflag = INTDATA(ARG(0,u));
                   if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == '*' &&
                      FUNCTOR(ARG(1,ARG(0,u))) == COS &&
                      FUNCTOR(ARG(0,ARG(1,ARG(0,u)))) == '*' &&
                      iseven(ARG(0,ARG(1,ARG(0,u))))
                     )
                      cosflag = -INTDATA(ARG(0,ARG(0,u)));
                 }
              if(cosflag * oneflag > 0)
                 { o[i] = doublecos5; ++i; /* cos 2� + 1 = 2cos^2 � */
                 }
              else if(cosflag * oneflag < 0 &&
                      ( problemtype != TRIG_IDENTITY || get_trigpolyflag() != SIN)
                     )
                 { o[i] = doublecos6; ++i;  /* cos 2� - 1 = - 2 sin^2 � */
                 }
              else if(problemtype!= TRIG_IDENTITY || !get_trigpolyflag())
                 { o[i] = doublecos4; ++i; /* cos 2� = cos^2 � - sin^2 � (must be tried last in auto mode)*/
                 }
              /* These have to be done in pre-ops or they'll get
                 preempted when postops hits the cosine term. */
            }
         for(k=0;k<n;k++)
            { u = ARG(k,t);
              if(NEGATIVE(u))
                 u = ARG(0,u);
              if(!FRACTION(u))
                 break;
            }
         if(k==n &&
            (!limitflag || (pathlength >= 2 && path[pathlength-2]!= LIMIT)) &&
           /* don't add fractions when limsum could be used.  If the
              individual limits are indeterminate then eventually
              commondenom will be used to add them. */
            (
              !iscomplex(t) ||
              n > 2  ||
              complex_addfractions_conditions(t)
            )
           )
            { /* all fractions */
              o[i] = addfractions; ++i;
              /* e.g. in common denom problems, if the denoms are the
                 same or ESPECIALLY if they differ only by a sign
                 as in 1-x^2 and x^2-1,  add the fractions before
                 factoring the denoms and looking for a common denom. */
            }
         if(problemtype == INTEGRATION && INDICATES(tflag,ATAN) && INDICATES(tflag,TAN))
            { o[i] = atantan2; ++i; /* atan (tan x) = x+c1  */
            }
         /* Are there two logarithms which ought to be collected before
            something happens to block the collection?
            Examples: log(6x) - log x
                      log((x+a)^2) - log(x^2-a^2)
         */
         if( (g = twologs(t)) != 0 && forced_logcollect(g,t))
            { if(g == LN)
                 { o[i] = collectlns2; ++i;
                   o[i] = collectlns; ++i;
                   o[i] = attractlns; ++i;
                 }
              else if (g == LOG)
                 { o[i] = collectlogs2; ++i;
                   o[i] = collectlogs; ++i;
                   o[i] = attractlogs; ++i;
                 }
              else if(g == LOGB)
                 { o[i] = collectlogb2; ++i;
                   o[i] = collectlogb; ++i;
                   o[i] = attractlogb2; ++i;
                 }
            }
         *nops = i;
         return;
      case '*' :
         pre_product(t,o+i,&k);
         *nops = i+k;
         return;
      case '^' :
         u = ARG(0,t);
         v = ARG(1,t);
         if(ISINTEGER(u) && FUNCTOR(v) == '*' && ISINTEGER(ARG(0,v)))
            /* example:  2^(2n)  becomes (2^2)^n which will become 4^n;
               powertopower will not be used in preops on (2^2)^n so
               no loop will arise.
            */
            { o[i] = reversepowertopower1; ++i;
            }
         if(FRACTION(u) && ZERO(ARG(1,u)) && iseven(v))
            /* (1/0)^2 becomes 1/0^2 which becomes infinity, not undefined */
            { o[i] = quotienttopower; ++i;
            }
         if(ZERO(v))
            { o[i] = zeroexponent; ++i;
              *nops = i;
              return;
            }
         else if(ONE(v))
            { o[i] = unitexponent; ++i;
              *nops = i;
              return;
            }
         if(ZERO(u))
            { o[i] = zerobase; ++i;
              *nops = i;
              return;
            }
         if(ONE(u))
            { o[i] = unitbase; ++i;
              *nops = i;
              return;
            }
         if(INTEGERP(u) && ONEHALF(v) && radicalflag >= 0)
            { /* change 2^(1/2) to sqrt(2) */
              o[i] = exponenttosqrt; ++i;
            }
         if(equals(u,complexi))
            { o[i] = defnofi; ++i;    /* i^2 = -1       */
              o[i] = powersofi0; ++i; /* i^(4n) = 1    */
              o[i] = powersofi1; ++i; /* i^(4n+1) = i  */
              o[i] = powersofi2; ++i; /* i^(4n+2) = -1 */
              o[i] = powersofi3; ++i; /* i^(4n+3) = -i */
            }
         if(INTEGERP(u) && contains(v,LOGB))
            { o[i] = writeintegeraspower; ++i;
            }
         if(equals(u,eulere))
            { if(currenttopic != _polar_form)
                 { o[i] = etotheipi; ++i;
                   o[i] = etotheminusipi; ++i;
                 }
              o[i] = etothei2npi; ++i;
              o[i] = etothecoterminal; ++i;
              if(constant(v) && contains(v,LN))
                /* example, e^(2 ln 2)  should get simplified to 2^2;
                   but we don't want to loop with introducelninexponent,
                   which makes x^y into e(y ln x). */
                { if(FUNCTOR(v) == LN)
                     { o[i] = lninexponent; ++i;
                     }
                  else if(FUNCTOR(v) == '*')
                     { o[i] = lninexponent2; ++i;
                     }
                }
            }
        /* catch e^(- ln x) */
         if(equals(u,eulere) && NEGATIVE(ARG(1,t)) &&
            FUNCTOR(ARG(0,v)) == LN
           )
            { o[i] = eliminatenegexp; ++i;
              *nops = i;
              return;
            }
        /* catch 10^(- log x) */
         if(equals(u,ten) && NEGATIVE(v) &&
            FUNCTOR(ARG(0,v)) == LOG
           )
            { o[i] = eliminatenegexp; ++i;
              *nops = i;
              return;
            }
        /* catch b^(- log(b,x) */
         if(ATOMIC(u) && NEGATIVE(v) &&
            FUNCTOR(ARG(0,v)) == LOGB
            && equals(ARG(0,ARG(0,v)),u)
           )
            { o[i] = eliminatenegexp; ++i;
              *nops = i;
              return;
            }
         if(NEGATIVE(v) && RATIONALP(ARG(0,v)) &&
            FUNCTOR(u) == '+' &&
            pathlength >= 2 &&
            path[pathlength-2] == INTEGRAL &&
            path[pathlength-1] == 1
           )
            { o[i] = eliminatenegexp; ++i;
              /* example, integral((1+e^(-x))^(-1/2),x).  This
              should become integral(1/(1+e^(-x))^(1/2),x), or
              else it won't complete in auto mode. This opens the
              way for a trig substitution. */
            }
         /* catch x^(p/log(b,x)) */
         if(FRACTION(v) && FUNCTOR(ARG(1,v)) == LOGB && equals(ARG(1,ARG(1,v)),u))
            { o[i] = introducelogbinexponent; ++i;
            }
         if(FRACTION(v) && FUNCTOR(ARG(1,v)) == LOG && equals(ARG(0,ARG(1,v)),u))
            { o[i] = introduceloginexponent; ++i;
            }
         if(FRACTION(v) && FUNCTOR(ARG(1,v)) == LN && equals(ARG(0,ARG(1,v)),u))
            { o[i] = introducelninexponent; ++i;
            }
         if(FRACTION(v) && FUNCTOR(ARG(1,v)) == '*')
            { for(j=0;j<ARITY(ARG(1,v));j++)
                 { if(FUNCTOR(ARG(j,ARG(1,v))) == LOGB && equals(ARG(1,ARG(j,ARG(1,v))),u))
                      { o[i] = introducelogbinexponent; ++i;
                        break;
                      }
                   if(FUNCTOR(ARG(j,ARG(1,v))) == LN && equals(ARG(0,ARG(j,ARG(1,v))),u))
                      { o[i] = introducelninexponent; ++i;
                      }
                   if(FUNCTOR(ARG(j,ARG(1,v))) == LOG && equals(ARG(0,ARG(j,ARG(1,v))),u))
                      { o[i] = introduceloginexponent; ++i;
                      }
                 }
            }
         if(NEGATIVE(u) && ONE(ARG(0,u)))  /* (-1)^n */
            { if(NEGATIVE(v) && status(powerofminusone)<=LEARNING)
                 { o[i] = eliminateconstnegexp; ++i;
                 }
              o[i] = intpowerofminusone; ++i;
              o[i] = powerofminusone; ++i;
            }
         if(ISINTEGER(u) && FRACTION(v) &&
            ISINTEGER(ARG(1,v)) && ISINTEGER(ARG(0,v)) &&
            /* don't fool around with bignums here */
            !ZERO(ARG(1,v))   /* zero denom can arise after evaluating
                                   a limit. Example:  3^(1/0) */
           )
            { if(equals(ARG(1,v),two))
                 { if(perfect_square(INTDATA(u)) &&
                      radicalflag < 0  /* sqrts will be converted to fractexps
                                          so go ahead and factor under exponents */
                     )
                       { o[i] = factorundersqrt; ++i;
                         *nops = i;
                         return;
                       }
                 }
              if(perfect_power(INTDATA(u),INTDATA(ARG(1,v))) &&
                 radicalflag <= 0    /* 0 is allowed here and not just above
                                            because in the above case, backtosqrts
                                            will be called, but not here. */
                )
                 { o[i] = factorunderroot; ++i;
                   *nops = i;
                   return;
                 }
            }
         if(INTEGERP(u) && INTEGERP(v) && !toplevel_arithmetic &&
            (currenttopic == _numerical_exponents || !contains_big_exponents(t))
           )
            { o[i] = arithmetic; ++i;
              /* otherwise we never even evaluate 2^3 in topic numerical exponents */
            }
         g = FUNCTOR(u);
         switch(g)
            { case SQRT:
                 o[i] = powerofsqrt; ++i;
                 if(radicalflag == -1)
                    { o[i] = powersqrtexp; ++i;
                    }
                 break;
              case ROOT:
                 o[i] = powerofroot; ++i;   /*  (��x)� = x          */
                 o[i] = powerofroot4; ++i;  /* root(mn,x)^n = root(m,x) */
                  /* this will also produce sqrt, imitating powerofroot4,
                     so there's no need to call that separately */
                 /* powerofroot2 and powerofroot3 are in postops.c  */
                 if(radicalflag == -1)
                    { o[i] = powerrootexp; ++i;
                    }
                 break;
              case '^':
                 if(!ISINTEGER(ARG(0,u)) || !ISINTEGER(ARG(1,u)))
                    /* but leave (2^2)^n alone so it can become 4^n */
                    { o[i] = powertopower; ++i;
                    }
                 if(
                     (ISINTEGER(ARG(1,u)) && RATIONALP(v)) ||
                     (ISINTEGER(v) && RATIONALP(ARG(1,u))) ||
                     (RATIONALP(ARG(1,u)) && RATIONALP(v))
                   )
                    { /* example:  (2^3)^(1/3) */
                      term temp;
                      value(product(ARG(1,u),v),&temp);
                      if(ISINTEGER(temp))
                         { o[i] = powertopower; ++i;
                         }
                    }
                 break;
              case COS:
                 if((trigexpandflag & 1) && FRACTION(ARG(0,u)))
                    { o[i] = cossqhalf; ++i;
                    }
                 if(NEGATIVE(ARG(0,u)))
                    { o[i] = cossqeven; ++i;
                    }
                 break;
              case SIN:
                 if((trigexpandflag & 1) && FRACTION(ARG(0,u)))
                    { o[i] = sinsqhalf; ++i;
                    }
                 if(NEGATIVE(ARG(0,u)))
                    { o[i] = sinsqeven; ++i;
                    }
                 break;
              case TAN:
                 if(NEGATIVE(ARG(0,u)))
                    { o[i] = tansqeven; ++i;
                    }
                 break;
              case SEC:
                 if(NEGATIVE(ARG(0,u)))
                    { o[i] = secsqeven; ++i;
                    }
                 break;
              case CSC:
                 if(NEGATIVE(ARG(0,u)))
                    { o[i] = cscsqeven; ++i;
                    }
                 break;
              case '+':  /* catch (sin x + cos x)^2 */
                 if(ARITY(u) == 2 &&
                    (
                     (FUNCTOR(ARG(0,u)) == SIN && FUNCTOR(ARG(1,u)) == COS) ||
                     (FUNCTOR(ARG(0,u)) == COS && FUNCTOR(ARG(1,u)) == SIN)
                    ) &&
                    equals(ARG(0,ARG(0,u)),ARG(0,ARG(1,u)))
                   )
                    { o[i] = squareofsum; ++i;
                    }
                 break;
            }
         if(!ATOMIC(v))
            { h = FUNCTOR(v);
              if(!ATOMIC(u) &&
                 FUNCTOR(u) == '/' &&
                 FUNCTOR(v) == '-'
                )
                 { o[i] = negexpofquotient; ++i;
                   *nops = i;
                   return;
                 }
              if(
                 (get_polyvalnegexpflag() == -1 ||
                  (!equals(u,eulere) && !get_infractionflag() && get_polyvalnegexpflag() <=0) ||
                  /* because it looks silly to leave x^(-3) + 1/x^2 alone */
                  /* but don't eliminate negative exponents of e because they
                     don't look silly.  */
                  (get_polyvalnegexpflag() == 2 && !iscomplex(t))  ||
                  ( limfractflag == -1  /* in a fraction in a limit */
                    && ( (pathlength >= 2 && path[pathlength-2] == '+') ||
                         (pathlength >= 4 && path[pathlength-4] == '+' && path[pathlength-2] == '-')
                       )
                    /*  e.g. lim(h->0,((3+h)^-1 - 3^-1)/h)  */
                  )
                 )
                 && !difflag && !intflag && !indexflag && !seriesflag
                )
                 { if(NEGATIVE(u))
                      { o[i] = minustopower; ++i;
                      } /* example: (-(1/2))^(-3) */
                   else
                      { o[i] = eliminateconstnegexp; ++i;
                      }
                 }
              if(!SOLVETYPE(problemtype))
                 { switch(h)
                      { case LOG:
                           o[i] = loginexponent; ++i;
                           break;
                        case LN :
                           o[i] = lninexponent;  ++i;
                           break;
                        case LOGB:
                           o[i] = logbinexponent; ++i;
                           break;
                        case '*' :
                           if(!difflag && !intflag && !limitflag &&
                              contains_at_toplevel(v,LN)
                             )
                             /* leave the base constant when differentiating
                                or integrating */
                              { o[i] = lninexponent2; ++i;
                              }
                           if(!difflag && contains_at_toplevel(v,LOG))
                              { o[i] = loginexponent2; ++i;
                              }
                           if(contains_at_toplevel(v,LOGB))
                              { o[i] = logbinexponent2; ++i;
                              }
                           break;
                      }
                 }
            }
         if(  !(pathlength >=2 &&
                (path[pathlength-2] == LOGB ||
                 path[pathlength-2] == LOG ||
                 path[pathlength-2] == LN
                )
               ) &&
              (
               (INTEGERP(u) && INTEGERP(v) && !contains_big_exponents(t))
               || (arithflag.negexp && !INTEGERP(v))
                  /* arithflag.negexp is set only for advanced problem
                     types; example: 4^(5-3) will be done in one
                     step when this is set, instead of two */
               || equals(u,minusone)  /* otherwise (-1)^2 won't be done */
              )
           )
            { o[i] = arithmetic; ++i;
            }
         if(arithflag.complex &&
            (
             (equals(u,complexi) && get_complex() && INTEGERP(v))
              || arithflag.negexp
             )
            )
             { o[i] = weakcomplexarithmetic; ++i;
             }
         break;
      case '/' :
         num = ARG(0,t);
         denom = ARG(1,t);
         g = FUNCTOR(num);
         h = FUNCTOR(denom);
         if(FUNCTOR(denom) == '^' && ZERO(ARG(0,denom)))
            { if(equals(ARG(1,denom),two))
                 { if(equals(num,infinity))
                      { o[i] = infinityoverzerosq; ++i;
                      }
                   else if(!NOTDEFINED(num))
                      { o[i] = zerosqdenom; ++i;
                        o[i] = zerosqdenom2; ++i;
                      }
                 }
              else if(iseven(ARG(1,denom)))
                 { if(equals(num,infinity))
                      { o[i] = infinityoverzero2n; ++i;
                      }
                   else if(!NOTDEFINED(num))
                      { o[i] = zero2ndenom; ++i;
                        o[i] = zero2ndenom2; ++i;
                      }
                }
            }
         if(ZERO(denom))
            { if(equals(num,infinity))
                 { o[i] = infinityoverzero;++i;
                   o[i] = infinityoverzero2;++i;
                   o[i] = infinityoverzero3;++i;
                 }
              else if(!contains_zero_denom(num) &&
                      !contains(num,UNDEFINED) &&
                      !contains(num,INFINITY)
                     )
                 { o[i] = zerodenom; ++i;
                   o[i] = zerodenom2; ++i;
                   o[i] = zerodenom3; ++i;
                 }
              if(g=='-')
                 { o[i] = minusoutfromnum; ++i;
                 }
              if(g == '+')
                 { o[i] = minusoutfromnum2; ++i;
                 }
              *nops = i;
              return;
            }
         if(ISZERO(num))
            { o[i] = zeronum; ++i;
              *nops = i;
              return;
            }
         if(ISONE(denom))
            { o[i] = unitdenom; ++i;
              *nops = i;
              return;
            }
         if(ISONE(num) && FRACTION(denom))
            { o[i] = invertandmultiply2; ++i;
              *nops = i;
              return;
            }
         if(get_complex() &&
            (complexexpression(num) &&
             (!complexexpression(denom) || !contains(denom,'+'))
            )
           )
            { o[i] = complexform; ++i;
              /* example:  (2+i)/2i -> 1/2 -i */
              /* but we don't want to use it on  )1+i)/(1-i) etc.,
                 where we need to show more steps */
            }
         if(get_complex() &&
            (
              (h == '^' && equals(ARG(0,denom),eulere) && iscomplex(ARG(1,denom))) ||
              (h == '*' && contains(denom,'e') && iscomplex(denom))
            )
           )
            { o[i] = complexexptonum; ++i;
            }
         if(contains_fract(denom) && contains_fract(num))
            { o[i] = differenceofsquares; ++i;
            }
         x = get_eigenvariable();
         /* when integrating  1/quadratic, it's better to complete the
            square rather than factor by quadratic formula and then
            use partial fractions.  After completing the square and
            substituting you get something that integrates to a ratio of
            logs.  However, for other rational functions you go ahead and
            factor and use partial fractions, if a substitution doesn't
            work first.
         */
         if(intflag && path[pathlength-2]==INTEGRAL &&
            FUNCTOR(num) == TAN && FUNCTOR(denom) == SEC
            && equals(ARG(0,num),ARG(0,denom))
           )
            { /* rewrite tan x/sec x  as cos x tan x, so it will
                 then go to sin x, when it's the integrand.
                 Otherwise this integral will be done by u = sec x,
                 which is unecessarily fancy. */
              o[i] = secrecip; ++i;
            }
         if(intflag && ONE(num) &&
            ispolyin(denom,x) &&
            path[pathlength-2]==INTEGRAL
           )
            { makepoly(denom,x,&v);
              if(DEGREE(v) == 2)
                 { o[i] = completethesquare1; ++i;
                   *nops = i;
                   return;
                 }
            }
         if(g == LIMIT && INTEGERP(denom))
            { o[i] = pulloutrational; ++i;
              *nops = i;
              return;
            }
         if(g == '*' && h != '/' &&
            !(h == '*' && contains_at_toplevel(denom,'/'))
           )
            { for(j=0;j<ARITY(num);j++)
                 { if(FRACTION(ARG(j,num)))
                      { o[i] = compoundfractions4; ++i;
                        *nops = i;
                        return;
                      }
                 }
            }
         if(g ==h)
            switch(g)
               { case '-' :
                    o[i] = cancelminusinquotient; ++i;
                    break;
                 case '+' :  /*  (x-y)/(x-�y) should get factored */
                    if(!(trigexpandflag & 8))
                       /* don't factor if all trig functions occur
                          to even powers  */
                       { o[i] = differenceofsquares; ++i;
                       }
                    if(ARITY(num) == 2 && ARITY(denom) == 2 &&
                       (trigexpandflag & 1)   /* not all trig functions have same arg */
                      )
                       { o[i] = trigsuminfraction; ++i;
                         /* Example: (cos 2x - cos 6x)/(sin 6x - sin 2x),
                            we need to apply difofcos in the num and difofsin
                            in the denom, but if we don't do it here, then
                            difofsin is applied in the denom and the resulting
                            cos 2x is rewritten sin^2 - cos^2, ruining the
                            solution. */
                       }
                    break;
                 case '^':
                    if(intflag && path[pathlength-2]==INTEGRAL &&
                       FUNCTOR(ARG(0,num))==SIN &&
                       FUNCTOR(ARG(0,denom)) == COS &&
                       equals(ARG(1,num),ARG(1,denom)) &&
                       ISATOM(ARG(0,ARG(0,num))) &&
                       equals(ARG(0,ARG(0,num)),ARG(0,ARG(0,denom)))
                      )
                       { /* integrating sin� / cos� */
                         o[i] = tanrule2; ++i;
                       }
                    if(intflag && path[pathlength-2]==INTEGRAL &&
                       FUNCTOR(ARG(0,num))== COS &&
                       FUNCTOR(ARG(0,denom)) == SIN &&
                       equals(ARG(1,num),ARG(1,denom)) &&
                       ISATOM(ARG(0,ARG(0,num))) &&
                       equals(ARG(0,ARG(0,num)),ARG(0,ARG(0,denom)))
                      )
                       { /* integrating cos�/sin� */
                         o[i] = cotrule2; ++i;
                       }
                    if(RATIONALP(ARG(1,num)) &&
                       equals(ARG(1,num),ARG(1,denom)) &&
                       get_polyvalnegexpflag() != 1 &&
                       FUNCTOR(ARG(0,num)) != '^' &&
                       FUNCTOR(ARG(0,denom)) != '^'
                       /* example, if denom is (2^3)^1/3 we don't
                          want to bring the 1/3 outside the fraction,
                          rather we want to wait till (2^3)^(1/3) becomes 2
                       */
                      )
                       { o[i] = poweroutoffraction; ++i;
                       }
                    break;
                 case SQRT:
                    if(INTEGERP(ARG(0,num))
                       && INTEGERP(ARG(0,denom))
                       && topflag
                       && nsquarefree(ARG(0,num))
                       && nsquarefree(ARG(0,denom))
                      )
                       { o[i] = quotientofsqrts; ++i;
                       }
                    break;

/* Example:   �(2/3) is left alone but �(2/3) + 5 is
   rewritten �2/�3 + 5 = (�2 + 5�3)/�3 = (�6 + 15) /3  */

                 case ROOT:
                    if(equals(ARG(0,num),ARG(0,denom))
                       && INTEGERP(ARG(1,num))
                       && INTEGERP(ARG(1,denom))
                       && topflag
                       && rootfree(ARG(1,num),(unsigned) INTDATA(ARG(0,num)))
                       && rootfree(ARG(1,denom),(unsigned) INTDATA(ARG(0,denom)))
                      )
                      /* chkinput ensures that indices of roots are
                         at most 0xffff, so the cast to unsigned  is
                         harmless, as no operator creates roots with
                         large indices.  */

                       { o[i] = quotientofroots; ++i;
                       }
                    break;
               }
         if(g == SIN && h == '+' && !cancel(ARG(0,num),two,&w,&q) && (trigexpandflag & 1))
            { o[i] = tanhalf1rev; ++i;  /* sin(2u)/(1+cos(2u)) = tan u */
              o[i] = cothalf2rev; ++i;  /* sin(2u)/(1-cos(2u)) = cot u */
            }
         if(h == SIN && g == '+' && !cancel(ARG(0,denom),two,&w,&q) && (trigexpandflag & 1))
            { o[i] = tanhalf2rev; ++i;  /* (1-cos 2u)/sin(2u) = tan u */
              o[i] = cothalf1rev; ++i;  /* (1+cos 2u)/sin(2u) = cot u */
            }
         if(g == '/' || h == '/')
            { o[i] = compoundfractions1; ++i; /*(a/c)/(b/c) = a/b */
            }
         if(g == '+' && !iscomplex(num))
            /* (-a-b)/c = -(a+b)/c, but not  (-a-bi)/c = -(a+bi)/c,
               because the latter must become -a/c - (b/c) i
            */

            { o[i] = minusoutfromnum2; ++i;
            }
         if(h == '+' && contains(denom, SQRT) && numerical(t))
            /* bring algebraic numbers to standard form */
            { o[i] = minusoutfromdenom2; ++i;
            }
         if(h == '*')
            /* get rid of compound fractions in the denominator
               before using cancelgcd */
            { int kk;
              unsigned short mm = ARITY(denom);
              for(kk=0;kk<mm;++kk)
                 { if(FRACTION(ARG(kk,denom)))
                      break;
                 }
              if(kk < mm)
                 { o[i] = invertandmultiply; ++i;
                 }
            }
         if(status(eliminatenegexp) > LEARNING && !stopcancel(t))
            { o[i] = cancelop; ++i;
              statusflag = 0;
              if(contains_sqrt(num) &&
                 !(numerical(t)) && /* leave sqrt(2)/2 alone */
                 ( pathlength <= 1 || problemtype >= LIMITS)
                   /* You need cancelsqrt2 desparately in L'Hopital's rule problems */
                )
                 { o[i] = cancelsqrt2; ++i;
                   o[i] = cancelroot2; ++i;;
                 }
              if(contains_sqrt(denom))
                 { o[i] = cancelsqrt; ++i;
                   o[i] = cancelroot; ++i;
                 }
            }
         else
            statusflag = 1;
         if(arithflag.negexp || !contains(t,'^'))
            { o[i] = arithmetic; ++i;
            }
         if(arithflag.complex)
            { o[i] = weakcomplexarithmetic; ++i;
            }
         if(
            (get_polyvalnegexpflag() <= 0 && !difflag && !intflag) ||
            (
             get_polyvalnegexpflag() == 2 &&
             !difflag && !intflag &&
             !iscomplex(ARG(0,t))
            )
           )
            /* by default eliminate neg exponents
               in numerators of fractions, except
               if those fractions are inside derivatives
               or integrals; but if polyvalnegexpflag is 2, as it
               is for _de_moivre, don't eliminate negative exponents
               if either the base or the power is complex.
            */
            { o[i] = eliminateconstnegexpnum; ++i;
            }
         o[i] = eliminatenegexpdenom; ++i;
         if(statusflag && !stopcancel(t))  /* see a few lines up */
            { o[i] = cancelop; ++i;  /* AFTER eliminatenegexpnum etc */
              if(contains_sqrt(num) || contains_sqrt(denom))
                 { o[i] = cancelsqrt; ++i;
                   o[i] = cancelroot; ++i;
                 }
            }

         if((g == '+' || g == '*' || g == '^') &&
            (h == '+' || h == '*' || h == '^') &&
            !stop_cancelgcd(num) &&
            !stop_cancelgcd(denom)
               /* first multiply out products of sums in the
                  num and denom; otherwise cancelgcd produces
                  correct but very mysterious black-box results */
           )
            { /* cancelgcd must go in pre_ops.  Example:
                 (cos x - 1)/ (cos^2 x -1)  should be cancelled,
                 but if we wait till post_ops, the denominator
                 will be sin^2 x instead.
                    On the other hand, we don't want it to work
                 on (-a^2 + c^2 + a^2 -2b^2+c^2)/((a-b)(a-c)(b-c)),
                 because the cancellations and collections should
                 be done first.
              */

              o[i] = cancelgcd; ++i;
              if(intflag && path[pathlength-2] == INTEGRAL &&
                 FUNCTOR(num) == '+' && FUNCTOR(denom) == '+'  /* don't use it if the denom is a power of x */
                )
                 { o[i] = polydivop; ++i;
                   /* this has to be here to pre-empt factoring in
                      the denom, which will take place when autosimp
                      calls pre_ops on the denominator. */
                 }
            }
         if(contains(t,SIN) && contains(t,COS))
                   /* example:   (1-sin^2 x)/cos^2 x =>  (cos^2 x)/cos^2 x */
                   /* instead of factoring the numerator, which will happen
                      when pre_ops hits the numerator.  */
            { o[i] = sinsquare2; ++i;
              o[i] = sinsquare3; ++i;
            }
         if(contains(t,CSC) && contains(t,COT))
                   /* example:   (csc^2x-1)/cot^2 x =>  (cot^2 x)/cot^2 x */
                   /* instead of factoring the numerator, which will happen
                      when pre_ops hits the numerator.  */
            { o[i] = cotsquare2; ++i;
            }
         if(contains(t,SEC) && contains(t,TAN))
                   /* example:   (sec^2x-1)/tan^2 x =>  (tan^2 x)/cot^2 x */
                   /* instead of factoring the numerator, which will happen
                      when pre_ops hits the numerator.  */
            { o[i] = tansquare2; ++i;
            }
         break;
      case SQRT:
         u  = ARG(0,t);
         if(radicalflag == -1 && /* in calculus past limits,
                                    radicalflag == -2, not -1 */
            pathlength >= 2 && path[pathlength-2] != LIMIT  &&
            !(pathlength >= 4 && path[pathlength-2] == '/' && path[pathlength-4] == LIMIT) &&
            /* don't rewrite sqrt into fractional exponents
               when it's just inside a limit, or when it's the numerator
               or denom of a fraction just inside a limit.  This is only
               needed when the sqrts are deeper inside. */
            !algebraic_number(u)  /* leave sqrt( 3/2 + 1/2 sqrt 5) alone  */
           )
            { if(INTEGERP(u) && currenttopic != _numerical_radicals)
                 { o[i] = knownroot; ++i;
                   /* it looks silly to write sqrt 4  as 4^(1/2)  */
                 }
              o[i] = sqrtexp; ++i;
              *nops = i;
              return;
            }
                  /* all these next few ops need to come BEFORE arithmetic,
                     e.g. to handle sqrt(2^100) without multiplying it out */
         if(INTEGERP(u) && currenttopic != _numerical_radicals)
            /* On that one topic, go ahead and factor 16 in sqrt(16) */
            { o[i] = knownroot; ++i;
            }
         if(OBJECT(u) || FUNCTOR(u) == '*')
            { o[i] = factorundersqrt; ++i;
            }
         if(OBJECT(u))
            { o[i] = evaltorational; ++i;
            }
         g = FUNCTOR(u);
         if(get_complex && (g == '-' || obviously_negative(u)))
            { o[i] = sqrtofminus1;++i;
              o[i] = sqrtofneg; ++i;
            }
         if( g=='*' || g == '^') 
            { if( !get_complex() || seminumerical(t))
                 { o[i] = sqrttoabs; ++i;
                 }
              if(get_complex()== 0 && !sqrtexp_conditions(ARG(0,u)))
                 { o[i] = sqrtofpower; ++i;
                   o[i] = sqrtsimp; ++ i;  /* sqrt(x^2y) = x sqrt y */
                 }
            }
         if(g == '/' && ONE(ARG(0,u)))
            { o[i] = sqrtofquotient; ++i;  /* sqrt(1/x) => 1/sqrt x */
              /* Must happen before squareeqn, otherwise we miss a
                 substitution in sqrt x = 2 sqrt 2 - sqrt(1/x), and
                 unnecessarily square, getting a 4th degree equation
                 instead of a quadratic */
            }
         if(INTEGERP(u))
            { o[i] = arithmetic; ++i;
            }
         if(arithflag.complex)
            { o[i] = weakcomplexarithmetic; ++i;
            }
         break;
      case ROOT:
         u = ARG(1,t);
         if(get_complex() && !iscomplex(u))
            { o[i] = complexrootminus; ++i;
            }
         if((radicalflag < 0 && !algebraic_number(u))|| intflag)
            { if(INTEGERP(u) && currenttopic != _numerical_radicals)
                 { o[i] = knownroot; ++i;
                 }
              if(currenttopic != _cubic_one_root &&
                 currenttopic != _complex_cubics
                )
                 { o[i] = rootexp; ++i;
                 }
            }
         if(equals(ARG(0,t),two))
            { o[i] = roottosqrt; ++i;
              *nops=i;
              return;
            }
         if(ISINTEGER(ARG(0,t)) && ISINTEGER(u) && currenttopic != _numerical_radicals)
            { o[i] = knownroot; ++i;
            }
         if(OBJECT(u) || FUNCTOR(u) == '*')
            { o[i] = factorunderroot; ++i;
            }
         g = FUNCTOR(ARG(1,t));
         if(g=='*' && radicalflag != -1)
            { o[i] = rootsimp; ++i;   /* ��(x�y) = x ��y */
            }
         if(g=='^' && radicalflag != -1 && !is_complex(ARG(1,t)))
            /* don't use these when what's under the root is complex */
            { o[i] = rootofpower; ++i;   /* root(n,x^n) = x if x>=0 or n odd */
              o[i] = rootofpower2; ++i;  /*  root(2n,x^n) = sqrt(x^n)  */
              o[i] = rootofpower4; ++i;  /* root(mn,a^n) = root(m,a) */
              o[i] = rootofpower3; ++i;  /* root(n,x^(nm)) = x^m if x>=0 or n odd */
              o[i] = rootsimp; ++i;       /* ��(x�y) = x ��y, works also
                                              with x^k instead of x�y */
              if(SOLVETYPE(problemtype))
                 { o[i] = rootofpower5; ++i;
                   /* root(3,x^2) = root(3,x)^2 for example */
                 }

            }
         if(INTEGERP(u))
            { o[i] = arithmetic; ++i;
            }
         if(arithflag.complex)
            { o[i] = weakcomplexarithmetic; ++i;
            }
         break;
      case COS:
         u = ARG(0,t);
         if(NEGATIVE(u))
            { o[i] = coseven; ++i;
            }
         if(OBJECT(u) && TYPE(u) == DOUBLE)
            { o[i] = devalop; ++i;
            }
         if(seminumerical(u) || (FUNCTOR(u) == DEG && numerical(ARG(0,u))))
            { select_trigeval_op(1,t,o+i,&k);
              i += k;
            }
         break;
      case SIN:
         u = ARG(0,t);
         if(NEGATIVE(u))
            { o[i] = sinodd; ++i;
            }
         if(OBJECT(u) && TYPE(u) == DOUBLE)
            { o[i] = devalop; ++i;
            }
         if(seminumerical(u) || (FUNCTOR(u) == DEG && numerical(ARG(0,u))))
            { select_trigeval_op(1,t,o+i,&k);
              i += k;
            }
         break;
      case TAN:
         u = ARG(0,t);
         if(NEGATIVE(u))
            { o[i] = tanodd; ++i;
            }
         if(OBJECT(u) && TYPE(u) == DOUBLE)
            { o[i] = devalop; ++i;
            }
         if(seminumerical(u) || (FUNCTOR(u) == DEG && numerical(ARG(0,u))))
            { select_trigeval_op(1,t,o+i,&k);
              i += k;
            }
         break;
      case COT:
         u = ARG(0,t);
         if(ZERO(u))
            { o[i] = cottotan; ++i;
            }
         if(NEGATIVE(u))
            { o[i] = cotodd; ++i;
            }
         if(seminumerical(u) || (FUNCTOR(u) == DEG && numerical(ARG(0,u))))
            { select_trigeval_op(1,t,o+i,&k);
              i += k;
            }
         break;
      case SEC:
         u = ARG(0,t);
         if(ZERO(u))
            { o[i] = secrule; ++i;
            }
         if(NEGATIVE(u))
            { o[i] = seceven; ++i;
            }
         if(problemtype == DIFFERENTIATE_FROM_DEFN
            && limitflag && !difflag
           )
            { o[i] = secrule; ++i;
            }
         if(seminumerical(u) || (FUNCTOR(u) == DEG && numerical(ARG(0,u))))
            { select_trigeval_op(1,t,o+i,&k);
              i += k;
            }
         break;
      case CSC:
         u = ARG(0,t);
         if(ZERO(u))
            { o[i] = cscrule; ++i;
            }
         if(NEGATIVE(u))
            { o[i] = cscodd; ++i;
            }
         if(problemtype == DIFFERENTIATE_FROM_DEFN
            && !difflag
           )
            { o[i] = cscrule; ++i;
            }
         if(seminumerical(u) || (FUNCTOR(u) == DEG && numerical(ARG(0,u))))
            { select_trigeval_op(1,t,o+i,&k);
              i += k;
            }
         break;
      case ASIN:
         if(FUNCTOR(ARG(0,t)) == SIN)
            { o[i] = asinsin; ++i;
              /* example, arcsin(sin(pi/12)).  If we don't do this in
                 preops, we lose our chance as sin(pi/12) gets transformed. */
            }
         break;
      case ACOS:
         if(FUNCTOR(ARG(0,t)) == COS)
            { o[i] = acoscos; ++i;
              /* example, arccos(cos(pi/12)).  If we don't do this in
                 preops, we lose our chance as sin(pi/12) gets transformed. */
            }
         break;
      case ATAN:
         if(FUNCTOR(ARG(0,t)) == TAN)
            { o[i] = atantan; ++i;
              /* In pre_ops to beat tan x = sin x / cos x  to the punch;
                 also to beat tan(x/2)... inside the atan */
            }
         break;

      case LN:
         u = ARG(0,t);
         if(
             (FRACTION(u) && ONE(ARG(0,u))) ||
             (FUNCTOR(u) == ABS && FRACTION(ARG(0,u)) && ONE(ARG(0,ARG(0,u))))
           )
            { o[i] = lnofreciprocal; ++i;
            }
         if(ISATOM(u))
            { if(equals(u,complexi))
                 { o[i] = lnofi; ++i;
                 }
            }
         switch(FUNCTOR(u))
            { case SQRT:
                if(!logcollectflag)
                    { o[i] = lnsqrt; ++i;
                    }
                 break;
              case ROOT:
                 if(!logcollectflag)
                    { o[i] = lnroot; ++i;
                    }
                 break;
              case '^':
                 if(equals(eulere,ARG(0,u)))
                    { o[i] = lnofpowerofe; ++i;
                    }
                 if(!logcollectflag && !limitflag)
                    { o[i] = lnofpower; ++i;
                    }
                 else if(contains_log(ARG(1,u)) &&
                         !stoplogofpower(u)
                        )
                    { o[i] = lnofpower; ++i;
                    }
                 else if(limitflag &&
                         !(FUNCTOR(ARG(0,u)) == '+' && ARITY(ARG(0,u)) == 2 &&
                           ONE(ARG(0,ARG(0,u))) &&
                           equals(ARG(1,ARG(0,u)), reciprocal(ARG(1,u)))
                           /* lim ln (1 + h/x)^(x/h) arises in differentiating
                              ln x from definition and the derivation
                              is ruined if we use lnofpower on it. */
                          )
                        )
                    { /* use lnofpower on limits of  ln(t^2) or t ln(t^2)
                         or ln(t^2)/t or t/ln(t^2).  But, in a sum,
                         we use attractlns instead.  So check that only
                         / and * are on the path between here and the LIMIT
                      */
                      for(j = pathlength-2; j>= 0; j--)
                         { if(path[j] == LIMIT)
                              { o[i] = lnofpower; ++i;
                                break;
                              }
                           if(path[j] != '*' && path[j] != '/')
                              break;
                         }
                    }
                 break;
              case '-':
                 if(ONE(ARG(0,u)))
                    { o[i] = lnofminusone; ++i;
                    }
                 break;
            }
         break;
      case LOGB:
         u = ARG(1,t);
         if(FUNCTOR(u) == '^' && equals(ARG(0,t),ARG(0,u)))
            { o[i] = logbofpowerofb; ++i;
            }
         if(FUNCTOR(u) == '^' && contains_log(ARG(1,u)) && !stoplogofpower(u))
            { o[i] = logbofpower; ++i;
              /* Example: log(3,x^log(3,x)) should go to log(3,x) log(3,x)
                 before the base of logs in the exponents gets changed.
                 But, log(2,a^log(a,4)) should NOT be touched, because
                 the inner term will be simplfied.
              */
            }
         if(FUNCTOR(u) == ROOT && !logcollectflag)
            { o[i] = logroot; ++i;
            }
         break;
      case LOG:
         u = ARG(0,t);
         switch(FUNCTOR(u))
            { case SQRT:
                 if(!logcollectflag)
                    { o[i] = logsqrt; ++i;
                    }
                 break;
              case ROOT:
                 if(!logcollectflag)
                    { o[i] = logroot; ++i;
                    }
                 break;
              case '^':
                 if(equals(ten,ARG(0,u)))
                    { o[i] = logofpowerof10; ++i;
                    }
                 if(!logcollectflag && !limitflag)
                    { o[i] = logofpower; ++i;
                    }
                 else if(contains_log(ARG(1,u)) && !stoplogofpower(u))
                    { o[i] = logofpower; ++i;
                    }
                 break;
            }
         break;
      case SUM:
         if( ISINFINITE(ARG(3,t)) &&
             ( problemtype == ADDSERIES ||
               (problemtype == TESTCONVERGENCE && currenttopic == _comparison_test)
             )
           )
           /* an infinite sum.  These operators try to bring a series
              to geometric or telescoping form and sum the series
              explicitly.  It's necessary to use these in comparison_test
              too so that the new series can eventually be added up.
           */

            { series_preops(t,o+i,&k);
              i += k;
            }
         break;
      case OR:
         if(problemtype == RELATED_RATES && pathlength <= 1)
            { *nops = 0;
              return;
            }
         if(problemtype == MINMAX)
            { o[i] = addcriticalpoints; ++i;
              o[i] = addendpoints; ++i;
              o[i] = addundefinedpoints; ++i;
              /* rejectpoint and tabulate are in postops */
            }
         if(SOLVETYPE(problemtype))
            { o[i] = collectmultiplesolns; ++i;
              if(!get_complex())
                { o[i] = introduceabs; ++i;
                }
            }
         if(problemtype == MINMAX)
            { o[i] = rejectpoint; ++i;
            }
         o[i] = lessthantole; ++i;
         o[i] = greaterthantoge; ++i;
         break;
      case AND:
         if(problemtype == LINEAR_EQUATIONS)
            { o[i] = dropeqn; ++i;
              if(currenttopic != _eqns_by_substitution)
                 { o[i] = varsleft; ++i;
                 }
              o[i] = evaluatedeterminant; i++;
                /* although pure automode needs this only under
                   topic _cramersrule, a user might invoke Cramer's Rule
                   in menu mode and then press Auto Finish.  So we
                   need it under other topics too. */
            }
         if(interval_as_and(t))
            { if(NEGATIVE(ARG(1,ARG(0,t))))
                 { o[i] = FUNCTOR(ARG(0,t)) == '<'  ? changesigns1 : changesigns2; ++i;
                 }
              o[i] = transfer; ++i;
            }
         break;
      case SG:
         o[i] = sgpos; ++i;
         o[i] = sgneg; ++i;
         if(FUNCTOR(ARG(0,t)) == '*')
            { o[i] = sgprod1; ++i;
            }
         else if(FRACTION(ARG(0,t)))
            { if(ONE(ARG(0,ARG(0,t))))
                 { o[i] = sgrecip2; ++i;
                 }
              else 
                 { o[i] = sgrecip3;++i;
                   o[i] = sgfract1; ++i;
                   o[i] = sgfract2; ++i;
                 }
            }
         else if(FUNCTOR(ARG(0,t)) == '^')
            { o[i] = sgpower; ++i;
            }
         break;
      case INTEGRAL:
         if(CANTFACTOR(t))  /* this integral has already been tried */
            { *nops = i;
              return;
            }
         if(pathlength == 4 && path[0] == '-' && path[2] == '-' &&
            equals(t,history(0))
           )
            { *nops = i;
              return;  // give up
            }            
         u = ARG(0,t);
         x = ARG(1,t);
         if(
            (FUNCTOR(u) == '*' || FRACTION(u)) &&
            contains(ARG(0,u),SG) &&
            !contains(ARG(1,u),SG)
           )
            { o[i] = sgint; ++i;
            }
         if(FUNCTOR(u) == DIFF || FUNCTOR(u) == PR)
            { o[i] = fundamentaltheorem; ++i;
                                }
         if(squareofone(u))  /* don't touch sin^4 x + 2cos^2 x sin^2 x + cos^4 x */
            { *nops = i;
              return;
            }
         if(ARITY(t) == 4)
            { term lo = ARG(2,t);
              term hi = ARG(3,t);
              if( (NEGATIVE(lo) && equals(ARG(0,lo),hi)) ||
                  (NEGATIVE(hi) && equals(ARG(0,hi),lo))
                )
                 { o[i] = oddintegrand; ++i;
                   o[i] = evenintegrand; ++i;
                 }
              o[i] = switchlimits; ++i;   /* make lower limit less than upper */
            }
         if(ARITY(t) == 4 &&
            (IMPROPER(t) || equals(ARG(2,t),minusinfinity) ||
             equals(ARG(3,t),infinity)
            ) &&
            status(integraltolimit) <= LEARNING
           )
            { if(FUNCTOR(ARG(0,t)) != ABS)
                /*  if the functor is ABS, breakabsint
                    should be used to eliminate ABS.  */
                 { if(equals(ARG(3,t),infinity))
                      { o[i] = insertpoint; ++i;
                                                                o[i] = intdivtest1; ++i;
                        o[i] = integraltolimit; ++i;
                      }
                   else if(equals(ARG(2,t),minusinfinity))
                      { o[i] = insertpoint; ++i;
                        o[i] = intdivtest2; ++i;
                        o[i] = integraltolimit2; ++i;
                      }
                   else if(IMPROPER(t))
                      { o[i] = insertpoint; ++i;
                        o[i] = integraltolimit3; ++i;
                        o[i] = integraltolimit4; ++i;
                      }
                 }
            }
         if(suppress_trig_expansion(ARG(0,t),x))
            { o[i] = intcossq; ++i;
              o[i] = intsinsq; ++i;
            }
         if(get_nextdefn())
            { o[i] = trysubstitution; ++i;
            }
         o[i] = changeintegrationvariable; ++i;
         g = FUNCTOR(u);
         switch(g)
            { case '+' :
                 if(status(intpoly) >= KNOWN && ispolyin(u,x))
                                                  { o[i] = intpoly; ++i;
                      *nops = i;
                      return;  /* intpoly is certain to work */
                    }
                 if(intsub_on_sum(u,x))
                    { o[i] = intsub; ++i;    /* before breaking up the sum */
                    }
                 if(!blockintlinearity(u,x))
                    { o[i] = intlinearity; ++i;  /* instead of just intsum */
                    }
                 break;
              case '-':
                 if(!contains(u,FUNCTOR(x)))
                    { o[i] = intconst; ++i;
                    }
                 o[i] = intminus; ++i;
                 break;
              case '^' :   /* catch f� x  where f is SEC, TAN, COT, CSC */
                 v = ARG(0,u);
                 h = FUNCTOR(v);
                 if(h == TAN &&
                    equals(ARG(0,v),x) &&
                    isinteger(ARG(1,u))
                   )
                    { o[i] = intsubtan; ++i;
                    }
                 if(h == COT &&
                    equals(ARG(0,v),x) &&
                    isinteger(ARG(1,u))
                   )
                    { o[i] = intsubcot; ++i;
                    }
                 if(h == SEC &&
                    equals(ARG(0,v),x) &&
                    isinteger(ARG(1,u))
                   )
                    { if(INTEGERP(ARG(1,u)))
                         { if(equals(ARG(1,u),two))
                              { o[i] = intsecsq; ++i;
                              }
                           else if(ISEVEN(ARG(1,u)))
                              { o[i] = intsubtan; ++i;
                              }
                           else
                              { o[i] = intsecpower; ++i;
                              }
                         }
                      if(!infer(even(ARG(1,u))))
                         { o[i] = intsubtan; ++i;
                         }
                      else
                         { o[i] = intsecpower; ++i;
                         }
                    }

                 if(h == CSC &&
                    equals(ARG(0,ARG(0,u)),x) &&
                    isinteger(ARG(1,u))
                   )
                    { if(INTEGERP(ARG(1,u)))
                         { if(equals(ARG(1,u),two))
                              { o[i] = intcscsq; ++i;
                              }
                           else if(ISEVEN(ARG(1,u)))
                              { o[i] = intsubcot; ++i;
                              }
                           else
                              { o[i] = intcscpower; ++i;
                              }
                         }
                      if(!infer(even(ARG(1,u))))
                         { o[i] = intsubcot; ++i;
                         }
                      else
                         { o[i] = intcscpower; ++i;
                         }
                    }
                 break;
              case SIN:
              case COS:
              case TAN:
                 if(FUNCTOR(ARG(0,u))==SQRT &&
                    equals(ARG(0,ARG(0,u)),x)
                   )
                    { o[i] = intsub; ++i;
                    }
                 break;
              case '*' :
                 if(
                    FUNCTOR(u) == '*' &&
                    !contains_at_toplevel(u,'/') &&
                    !RATIONALP(ARG(0,u))
                    /* multiply the fractions together before bringing
                       out a constant unless it's a rational number
                       as the first factor, because there might be
                       some cancellations in the integrand, e.g.
                       a sqrt(10) in the denom somewhere to cancel
                       a sqrt(10) as a toplevel factor. */
                   )
                    { o[i] = intlinear; ++i;
                    }
                 o[i] = inttosec; ++i;
                 o[i] = inttocsc; ++i;
                 if(!PRIME(t) && intsub_in_preops(u,ARG(1,t)) && !get_pending())
                    /* PRIME means integration by substitution has
                       been tried on it already.  The call to
                       get_pending prevents using intsub again while
                       you still are supposed to be simplifying du/dx */
                    /* example:  (x+3)(x^2+6x)^2  */
                    { if(status(intsub) >= KNOWN)
                         { o[i] = intsub; ++i;
                         }
                      else if(status(intsub) >= LEARNING)
                         /* it won't be used in topic _simple_int */
                         { o[i] = choosesubstitution; ++i;
                         }
                    }
                 if(!iscomplex(t))
                    { o[i] = polyvalop; ++i;
                      /* It was not thrown in above to avoid preempting intsub */
                    }
                 break;
              case '/' :   /* pull out a constant */
                 num = ARG(0,u);
                 denom = ARG(1,u);
                 o[i] = intconst; ++i;
                 o[i] = intlinear; ++i;
                 if(equals(denom,x))
                    { o[i] = intrecip;  ++i;  /* before intsub is used */
                    }
                 else if(status(intsub) > LEARNING &&
                         (ARITY(t) == 2 ||
                          (!IMPROPER(t) &&
                           !equals(ARG(3,t),infinity) &&
                           !equals(ARG(2,t),minusinfinity) &&
                           !equals(ARG(3,t),minusinfinity) &&
                           !equals(ARG(2,t),infinity)
                                                                  )
                          ||
                          status(integraltolimit) > LEARNING
                         )
                        )
                    { if(FUNCTOR(denom) == '+' &&
                         (equals(ARG(0,denom),x) || equals(ARG(ARITY(denom)-1,denom),x))
                         )
                          { o[i] = intrecip2; ++i;
                          }
                      else
                          { o[i] = intrecip3; ++i;
                          }
                    }
                 /* The following operators go in pre_ops so they get tried
                    before the denominator is factored, e.g.
                    1/�(x^2-1) => 1/�((x-1)(x+1))
                    before it can get integrated.
                  */
                 if(ARITY(t) == 2 || !equals(ARG(3,t),infinity))
                    { o[i] = inttoatan; ++i;
                      o[i] = inttolnratio1; ++i;
                      o[i] = inttolnratio2; ++i;
                    }
                 if(ONE(num) &&
                    (FUNCTOR(denom) == COS ||
                     (FUNCTOR(denom) == '^' && FUNCTOR(ARG(0,denom)) == COS)
                    )
                   )
                    { o[i] = secrule2; ++i;     /* 1/cos� = sec�  */
                    }
                 if(
                    (ARITY(t) == 2 || !equals(ARG(3,t),infinity)) &&
                    contains(ARG(1,ARG(0,t)),SQRT)
                   )
                    { o[i] = inttoasin; ++i;
                      o[i] = inttolnratio3; ++i;
                      o[i] = inttoacos; ++i;
                    }
                 if(!IMPROPER(t) && intsub_in_preops(u,x))
                        /* example:  (x+3)/(x^2+6x)^2  */
                    { if(status(intsub) >= KNOWN)
                         { o[i] = intsub; ++i;
                         }
                      else if(status(intsub) >= LEARNING)
                         { o[i] = choosesubstitution; ++i;
                         }
                    }
                 if(!iscomplex(t))
                    { o[i] = polyvalop; ++i;
                      /* It was not thrown in above to avoid preempting intsub */
                    }
                 break;
              case DIFF:
                 o[i] = fundamentaltheorem; ++i;
                 break;
            }
         break;

      case EVAL:
         if(FUNCTOR(ARG(0,t)) == LN && status(evalbar) > LEARNING)
            { o[i] = evalbarln; ++i;
            }
         o[i] = evalbar; ++i;
         break;

      case '=':
         x = get_eigenvariable();
         if(problemtype == MINMAX)
            { if(pathlength == 0)
                 { o[i] = addcriticalpoints; ++i;
                   o[i] = addendpoints; ++i;  /* could need this if there was
                                                 just one critical point */
                   o[i] = addundefinedpoints; ++i;
                 }
              o[i] = rejectpoint; ++i;
              o[i] = eliminateparameter; ++i;
            }
         if((problemtype == TRIG_IDENTITY || SOLVETYPE(problemtype)))
             /* sincosflag is used in autotrig to control the decision
                which of the three doublecos operators to use. */
            { if(contains_odd_power(t,SIN))
                 set_sincosflag(SIN);
              else if(contains_odd_power(t,COS))
                 set_sincosflag(COS);
              else
                 set_sincosflag(0);
              if((contains(t,COSH) || contains(t,SINH)) && contains(t,'e'))
                 set_hflag(1);
              else if(currenttopic == _hyperfunctions)
                 set_hflag(1);  /* under this topic you are supposed to
                 express hyperbolic functions as exponentials. */
              else
                 set_hflag(0);
              /* hflag helps control coshdef and sinhdef; for more info
                 see the comments at the definition of hflag in postops.c */
            }
         if((problemtype == TRIG_IDENTITY || SOLVETYPE(problemtype)) &&
             stricttrigpoly(ARG(0,t),x) &&
             stricttrigpoly(ARG(1,t),x)
           )
            { unsigned short localtrigflag = 0;
              localtrigflag = 0;
              set_trigflag(t,&localtrigflag);
              if(trigexpandflag && algebraic_identity(t))
                 trigpolyflag = -1;
              else if(trigexpandflag & (1 << 12))
                 { /* only sin and cos occur, so we need to write
                      the problem in the form  a sin t + b where
                      a and b are polys in cos t, or else in the
                      form a cos t + b where a and b are polys in
                      sin t, using sinoddpower or cosoddpower to
                      eliminate the odd powers.  What we have to
                      do now is determine which of these mutually
                      exclusive forms to use.
                         If one side of the identity is an even power
                      of COS and the other side only contains SIN,
                      then eliminate COS, and vice-versa.  Otherwise
                      choose SIN if COS appears to an odd power, or
                      COS if SIN appears to an odd power.  Otherwise,
                      arbitrarily choose to eliminate SIN.
                         But we shouldn't start eliminating sin in
                      favor of cos too soon.  Consider this example:
                      4 sin x cos x (cos^2 x - sin^2 x) =
                      4 sin x cos^3 x - 4 sin^3 x cos x,
                      which can be solved either by multiplying out on
                      the left or factoring on the right.  We don't want
                      to rewrite sin^2 x as 1-cos^2 on the left.  So,
                      we don't want to set trigpolyflag in such a case.
                      Indeed, if the two sides can be simplified to the
                      same thing without using trig identities, then
                      that's how it should be done.
                    */
                   trigpolyflag = tpf_aux(t,SIN,COS);
                 }
              else if(trigexpandflag & (1 << 4))
                 { trigpolyflag = tpf_aux(t,SEC,TAN);
                 }
              else if(trigexpandflag & (1 << 8))
                 { trigpolyflag = tpf_aux(t,COT,CSC);
                 }
              else
                 trigpolyflag = 0;
            }
         if(problemtype == TRIG_IDENTITY)
            /* don't miss a one-step solution just because the terms aren't
               in the proper order.  If this happens with a lot of sin 3x
               terms which will soon get expanded, you miss your chance if
               you don't do it on the '='.  */
            { if(FRACTION(ARG(0,t)) && FRACTION(ARG(1,t)))
                 { term u,v;
                   u = ARG(0,t);
                   v = ARG(1,t);
                   if(FUNCTOR(ARG(0,u)) == '+' && ARITY(ARG(0,u)) == 2 && NEGATIVE(ARG(1,ARG(0,u))) &&
                      FUNCTOR(ARG(1,u)) == '+' && ARITY(ARG(1,u)) == 2 && NEGATIVE(ARG(1,ARG(1,u))) &&
                      FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2 && NEGATIVE(ARG(1,ARG(0,v))) &&
                      FUNCTOR(ARG(1,v)) == '+' && ARITY(ARG(1,v)) == 2 && NEGATIVE(ARG(1,ARG(1,v)))
                     )
                      { o[i] = negatenumdenom; ++i;
                        /* (a-b)/(c-d) = (b-a)/(d-c) */
                      }
                 }
              if(
                 (FUNCTOR(ARG(0,t)) == '*' && !stop_orderfactors(ARG(0,t))) ||
                 (FUNCTOR(ARG(1,t)) == '*' && !stop_orderfactors(ARG(1,t)))
                )
                 { o[i] = orderfactors; ++i;
                 }
              if(!stop_orderterms(t))
                 { o[i] = orderterms; ++i;
                 }
              /* Also don't miss an identity that, after one side is
                 content-factored, will be an identity or will need only
                 one term-ordering step to be an identity. */
              u = ARG(0,t);
              v = ARG(1,t);
              if(FUNCTOR(v) == '*' && FUNCTOR(u) == '+' &&
                 !content_factor(u,&a,&b) &&
                 equal_mod_order(product(a,b),v)
                )
                 { o[i] = contentfactor; ++i;
                 }
              if(FUNCTOR(u) == '*' && FUNCTOR(v) == '*' &&
                 !content_factor(v,&a,&b) &&
                 equal_mod_order(u,product(a,b))
                )
                 { o[i] = contentfactor; ++i;
                 }
              /* is there a common factor on the two sides which we could possibly cancel?  */
              if(contains_trig(u) && contains_trig(v) && common_factor(u,v))
               /* the contains_trig call keeps us from using cancelling when 
                  verifying algebraic identities.  */
                 { o[i] = diveqn; ++i;
                 }
              /* is there a pair of factors on the two sides which are really identical 
                 but are not yet literally identical?  */
              o[i] = preparetocancel; ++i;
            }
         if(currenttopic == _logarithmic_differentiation)
            { if(!contains(t,DIFF))
                 { o[i] = difeqn; ++i;
                   break;
                 }
              if(FUNCTOR(t) == '=' &&
                 !contains(ARG(1,t),DIFF) &&
                 FRACTION(ARG(0,t)) &&
                 ( FUNCTOR(ARG(0,ARG(0,t))) == DIFF || FUNCTOR(ARG(0,ARG(0,t))) == PR)
                )
                 { o[i] = muleqn; ++i;
                 }
              break;
            }
         if(!SOLVETYPE(problemtype) &&
            !(problemtype == LINEAR_EQUATIONS && pathlength == 0)
           )
            { u = ARG(0,t);
              v = ARG(1,t);
              if(FUNCTOR(u) == FUNCTOR(v))
                 { g = FUNCTOR(u);
                   if(g == '^' && equals(ARG(0,u),ARG(0,v)))
                      { o[i] = logbeqn; ++i;
                        *nops = i;
                        return;
                      }
                   if(g == LN || g == LOG)  /* if we have ln u = ln v, make it u=v */
                      { o[i] = powereqn2; ++i;
                        *nops = i;
                        return;
                      }
                 }
              if(FUNCTOR(u) == '^' && INTEGERP(v))
                 { /* example, 5^(...) = 25 */
                   o[i] = logbeqn; ++i;
                 }
              if(
                 (FUNCTOR(u) == '*' || FUNCTOR(u) == '+') &&
                 (FUNCTOR(v) == '*' || FUNCTOR(v) == '+') &&
                 status(polyvalop) > LEARNING &&
                 /* don't use "common factor" in elementary algebra */
                 get_whichpass() > 0
                 /* and don't use it at all except as a last resort */
                )
                 { o[i] = factorandcancel; ++i; /* factor out gcd of u and v */
                 }
            }
         else
            { pre_equation(t,o+i,&j);
              i += j;
            }
         if(problemtype == INTEGRATION)
            { o[i] = difsubstitution; ++i;
            }
         else if(problemtype == INDUCTION && !equals(ARG(0,t),ARG(1,t)))
                     /* the second part prevents arithmetic from rewriting
                        a = a as true */
            { o[i] = arithmetic; ++i;
              o[i] = selectinductionvariable; ++i;
              o[i] = useinductionhyp; ++i;
            }
         break;
      case '>':
         o[i] = arithmetic; ++i;  /* reduce e.g. 0�1 to false */
         x = get_eigenvariable();
         if(contains(ARG(1,t),FUNCTOR(x)) && !contains(ARG(0,t),FUNCTOR(x)))
            { o[i] = reversegreaterthan; ++i;
            }
         pre_ineq(t,o+i,&j);
         i += j;
         break;
      case GE :
         o[i] = arithmetic; ++i;  /* reduce e.g. 0�1 to false */
         x = get_eigenvariable();
         if(contains(ARG(1,t),FUNCTOR(x)) && !contains(ARG(0,t),FUNCTOR(x)))
            { o[i] = reversege; ++i;
            }
         pre_ineq(t,o+i,&j);
         i += j;
         break;
      case '<':
         pre_ineq(t,o+i,&j);
         i += j;
         break;
      case LE :
         pre_ineq(t,o+i,&j);
         i += j;
         break;
      case LIMIT:
         u = LIMITAND(t);
         x = ARG(0,ARG(0,t));
         a = ARG(1,ARG(0,t));
         if(!contains(u,FUNCTOR(x)) || contains_deriv(u,x))
            /* Don't work on a limit till you've evaluated all
               derivatives in the limitand */
            { o[i] = limconst; ++i;
              *nops = i;
              return;
            }
         SaveShowStepState();
         if(!maximal_sub(u,&temp) &&
             (
              algpoly(temp) ||
              (ARITY(temp) == 1 && TRIGFUNCTOR(FUNCTOR(temp)) && equals(ARG(0,temp),x))
             )
           )
            /* example, (cos(x^2)-1)/x^2  which otherwise
               might be transformed to  sin^2(x/2) /(x/2),
               except that now we have code to get L'Hopital used on it.
            */
            { o[i] = changelimitvariable; ++i;
              changelimitvarflag = 1;
            }
         RestoreShowStepState();   /* maximal_sub can call SetShowStepArg */
         if(!contains_big_exponents(t) && !iscomplex(t))
            { o[i] = polyvalop; ++i;
            }
         if(equals(u,x))
            { o[i] = limident; ++i;
            }
         if(FUNCTOR(u) == '^' &&
            FUNCTOR(ARG(0,u))=='+' && ARITY(ARG(0,u)) == 2 &&
            (ONE(ARG(0,ARG(0,u))) || ONE(ARG(1,ARG(0,u))))
           )
            { if(FRACTION(ARG(1,u)))
                 { o[i] = defnofe; ++i;
                 }
              if(!changelimitvarflag && ISINFINITE(a) && equals(ARG(1,u),x))
                 { o[i] = changelimitvariable; ++i;
                 }
            }
         if(status(limpoly) >= KNOWN)
            { if(indenomflag && FUNCTOR(u) == '^' && iseven(ARG(1,u)))
                 { o[i] = limpower; ++i;
                   /* If you use limpoly on 1/x^2 you get 1/0 instead
                      of 1/0^2, so you can't get 'infinity' but only
                      undefined.  Therefore use limpower first. */
                 }
              else if(!FRACTION(u))
                 /* don't use limpoly on x/2 even though it will work;
                    and for non-constant denom it can't work. */
                 { o[i] = limpoly; ++i;
                 }
            }
         if(NEGATIVE(u))
            { o[i] = limlinear; ++i;  /* lim(x->0, -2 sin x) for example
                                   should go direct to -2 lim(x->0, sin x) */
              o[i] = limminus; ++i;
            }
         if(FUNCTOR(u) == '/' && OBJECT(ARG(0,u)) &&
            !NOTDEFINED(ARG(1,ARG(0,t))) &&
            !(
               FUNCTOR(ARG(1,u)) == SEC ||
               (FUNCTOR(ARG(1,u)) == '*' && contains(ARG(1,u),SEC)) ||
               FUNCTOR(ARG(1,u)) == CSC ||
               (FUNCTOR(ARG(1,u)) == '*' && contains(ARG(1,u),CSC))
             )  /* in the latter cases secrecip or cscrecip will be used */
                /* some case may be blocked here where SEC is buried deeper
                   in the term, but then it still should be simplified
                   before using limrecip.  contains_at_toplevel isn't enough
                   here because the denom may contain sec^2.
                */
            )
             /* example:  u = 2/x . Here limrecip will work
                directly:
                   lim 2/x => 2/lim x  rather than
                   lim 2/x => 2 lim 1/x => 2(1/lim x) = > 2/ lim x
                But !NOTDEFINED(a) so as not to do this on lim(x->0,1/x)
                which will be handled directly by another operator.
                If this condition changes, change autolimit's conditions
                for throwing in limrecip as a last resort on limits at
                infinity to match.
             */
            { o[i] = limrecip; ++i;
              *nops = i;
              return;
            }
         if(FUNCTOR(u) == '/' &&
            !changelimitvarflag &&
            !ATOMIC(ARG(0,u)) && ARITY(ARG(0,u)) == 1
            && equals(ARG(0,ARG(0,u)),ARG(1,u))  &&
            !equals(ARG(1,u),x)
           )
             /* e.g. sin(5t)/(5t)  */
            { o[i] = changelimitvariable; ++i;
              *nops = i;
              return;
            }
         if(FRACTION(u)  &&
            !changelimitvarflag &&
            !ATOMIC(ARG(1,u)) && ARITY(ARG(1,u)) == 1
            && equals(ARG(0,ARG(1,u)),ARG(0,u))  && !equals(ARG(0,u),x)
           )
             /* e.g.  5t/sin(5t)  */
            { o[i] = changelimitvariable; ++i;
              *nops = i;
              return;
            }
         if(FRACTION(u) && FUNCTOR(ARG(0,u)) == LN &&
            !changelimitvarflag &&
            FUNCTOR(ARG(0,ARG(0,u))) == '+' &&
            !ATOMIC(ARG(1,u)) &&
            (
             (ONE(ARG(0,ARG(0,ARG(0,u)))) && equals(ARG(1,u),ARG(1,ARG(0,ARG(0,u))))) ||
             (ONE(ARG(1,ARG(0,ARG(0,u)))) && equals(ARG(1,u),ARG(0,ARG(0,ARG(0,u)))))
            )
           )
             /* ln(1+u)/u ;  if e.g. u is a fraction don't use limlinear first */
            { o[i] = changelimitvariable; ++i;
            }
         if(FRACTION(u) && contains(ARG(1,u),'/') &&
            is_linear_in(ARG(1,u),x) && contains(ARG(1,u),FUNCTOR(x))
           )
            /* example, 4x-3/(x-1/2)  as x->1/2.  If we don't try limquotient
               in pre_ops, thrashing results due to pulling out 1/2 and putting
               it back in again. */
            { o[i] = limquotient; ++i;
            }
         if(FUNCTOR(u) == '*' || FUNCTOR(u) == '/')
            { o[i] = limlinear; ++i;
            }
         if(FUNCTOR(u) == '/' &&
            ZERO(a) &&
            (trigpolyargs2(ARG(1,u),x)==2 || trigpolyargs2(ARG(0,u),x)==2) &&
              /* trigpolyargs2 returns 2 if trig functions are actually present,
                 1 if its arg is really just a polynomial */
            (trigexpandflag & 1)  /* not all trig functions have the same arg */
           )
            /* example:  lim(x->0, (tan 2x) / tan 3x)
               A trigpoly2 is a polynomial in trig functions whose args are
               linear in x.   Divnumdenom has to be used in pre_ops because
               otherwise, trig identities will be used to reduce everything
               to trig functions of x, not 2x, 3x, etc., and
               the limitand will get horribly complicated.
            */
            { o[i] = divnumdenom; ++i;
            }
       break;
      case DET:
         o[i] = evaluatedeterminant; i++;
         break;
    } /* close big switch */
  *nops = i;
  return;
}  /* close function */

/*_______________________________________________________*/
int suppress_factoring(int problemtype, int dir)
/* return 1 if we are working on a sum  which is monomially contained
in another sum, as in 3x - 2(x^2-1); we don't want to factor the x^2-1;
EXCEPT when factoring that sum is going to make the outer sum factor
too, as in 3(y+1)^2 +11(y^2-1) -4(y-1)^2.  That form will be caught
and handled by factorquadratic specially, so
this function just goes ahead and suppresses factoring.
  Also return 1 when working on a sum whose parent and grandparent
are '/', i.e. is part of a fraction which is the num or denom of a
compound fraction.  In this case factoring should be postponed till
invertand multiply has been used.
  If dir == 0, we're going DOWN in autosimp, so the last functor
in that path is NOT the term we're working on.  If dir==1, we're
going up, so the last functor IS the term we're working on.
*/

{ int pathlength = get_pathlength();
  unsigned short const *path = get_path();
  int k = pathlength-1;
  if(pathlength == 0)
     return 0;
  if(dir == 1)
     { assert(path[k] == '+');
       k-=2;   /* ignore the functor of the current term */
     }
  else
    --k;  /* ignore the arg number */
  if(k >= 2 && path[k] == '/' && path[k-2] == '/')
     return 1;
  while(k >= 0 &&
           ( path[k] == '*' ||
             (path[k] == '^' && path[k+1] == 1) ||
             path[k] == '-'
           )
       )
      k -= 2;
  if(k < 0 || path[k] != '+')
     return 0;
  return 1;
}

/*_______________________________________________________________________*/
static int contains_sq2(unsigned short f, term t, term x)
/* if t has the form f^m(x) where m >= 2, or is a product,
one of whose factors has that form, then return 1; else return 0.
*/
{ unsigned short i,n;
  if(FUNCTOR(t) == '^' && ISINTEGER(ARG(1,t)) && INTDATA(ARG(1,t)) >= 2 && 
     FUNCTOR(ARG(0,t)) == f && equals(ARG(0,ARG(0,t)),x)
    )
     return 1;
  if(FUNCTOR(t) != '*')
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_sq2(f,ARG(i,t),x))
          return 1;
     }
  return 0;
}    

/*____________________________________________________________________*/
int intsub_in_preops(term u, term x)
/* Return 1 if integration by substitution should be tried
on an integrand with functor * or / before simplifying the
integrand.  We have to pre-empt multiplyout and apart,
because if these are used we lose our chance at substitution.
Here u is the integrand and x is the variable of integration.
  We also must intervene in case the integrand contains
ln(tan x), which may become ln(sin x) - ln(cos x) and the
integral broken up irretrievably before intsub gets tried.
  We must also pre-empt rationalizedenom in, for example,
1/(x-sqrt(x+2)), where u = sqrt(x+2) is the thing to do.
After rationalizedenom we do get a solution, but it's long
and complicated.
  And, in general we must preempt polyvalop too; see the
example in the code below near 'exponential_factor'.
  If the integrand is trigrational and all the trig args
are the same, we don't want to miss that opportunity, because
various trig operations can destroy it.
*/

{ unsigned short f = FUNCTOR(u);
  term base,power;
  assert(f == '*' || f == '/');
  if(status(intsub) == UNKNOWN && get_whichpass() == 0)
     return 0;
  if(logtrig(u))
     return 1;
  if(trigalg_same(u,x))
     return 1;
  if(exponential_factor(u,x) && !contains_trig(u))
     return 1;  /* e^(-t)ln(1+e^(-t))/(1+e^(-t)) for example */
                /* the !contains_trig clause is for  sin(t)/e^t  which should be done by parts */
  /* next trap  tan(x)/cos^2  and similar examples before tan = sin /cos is used */
  if(f == '/' && contains_sq2(COS,ARG(1,u),x))
    { term a,b,c,cossq;
      cossq = make_power(cos1(x),two);
      if(!cancel(ARG(1,u),cossq,&a,&b) && equals(a,cossq))
         { subst(var0, tan1(x),b,&c);
           if(!contains(c,FUNCTOR(x)))
              return 1;
         }
    }
  if(f == '/' && contains_sq2(SIN,ARG(1,u),x))
    { term a,b,c,sinsq;
      sinsq = make_power(sin1(x),two);
      if(!cancel(ARG(1,u),sinsq,&a,&b) && equals(a,sinsq))
         { subst(var0, cot1(x),b,&c);
           if(!contains(c,FUNCTOR(x)))
              return 1;
         }
    }
  if(f == '/' && FUNCTOR(ARG(0,u)) == '^' && ISINTEGER(ARG(1,ARG(0,u))) &&
     FUNCTOR(ARG(0,ARG(0,u))) == TAN && equals(ARG(0,ARG(0,ARG(0,u))),x) &&
     FUNCTOR(ARG(1,u)) == '^' && FUNCTOR(ARG(0,ARG(1,u))) == COS && 
     equals(ARG(0,ARG(0,ARG(1,u))),x) && equals(ARG(1,ARG(1,u)),two)
    ) 
     return 1;
  if(f == '/' && FUNCTOR(ARG(0,u)) == '^' && ISINTEGER(ARG(1,ARG(0,u))) &&
     FUNCTOR(ARG(0,ARG(0,u))) == COT && equals(ARG(0,ARG(0,ARG(0,u))),x) &&
     FUNCTOR(ARG(1,u)) == '^' && FUNCTOR(ARG(0,ARG(1,u))) == SIN && 
     equals(ARG(0,ARG(0,ARG(1,u))),x) && equals(ARG(1,ARG(1,u)),two)
    ) 
     return 1;
  
  if(f == '/' && FUNCTOR(ARG(0,u)) == '+' && FUNCTOR(ARG(1,u)) == '+')
     return 1;  /* preempt 'apart'-- it's possible that the numerator is
                   (a multiple of) the derivative of the denominator, and
                   we miss that substitution if we use apart. */
  if(!ispolyin(ARG(0,u),x))
     return 0;  /* Then post_ops is soon enough; we only have to
                   pre-empt  apart and multiplyout and partialfractionsop  */
  if(grat(u,x))
          /* grat tells if u is a rational function in x, but it allows
                  sums of products of powers of polynomials in num and denom,
                  not requiring strict polynomial/polynomial form.  See polynoms.c.
          */
     return 1;   /* example,  1/(x(x+1)^4).  If we use partial
                    fractions we wind up with 1/(x+1)^4 which
                    Mathpert can't do. */
  if(FUNCTOR(ARG(1,u)) == '^')
     { base = ARG(0,ARG(1,u));
       power = ARG(1,ARG(1,u));
       if(constant(power) && !ATOMIC(base) && ispolyin(base,x))
          return 1;  /* example:  (x+3)(x^2+6x)^2  */
       if(equals(base,eulere) &&
          ispolyin(power,x) &&
          contains(power,'^')  /* don't use subst on (2x+3)e^x, it will
                                  try u = 2x+3 .  In general (poly)e^(linear)
                                  should be multiplied out and split.
                               */
         )
          return 1;
     }
  if(possible_trigsub(u,x))
     return 0;  /* example,  x^3 sqrt(1-x^2);
                   if you substitute u = x^2, you are lost.
                */
  if(!contains(ARG(0,u),FUNCTOR(x)) &&
     FUNCTOR(ARG(1,u)) == SQRT &&
     ispolyin(ARG(0,ARG(1,u)),x)
    )
      return 0;   /* integral(1/sqrt(f(x)),x) doesn't get better by substitution */
  if(ARITY(ARG(1,u)) == 1 &&
     ispolyin(ARG(0,ARG(1,u)),x) &&
     contains(ARG(0,ARG(1,u)),'^')   /* don't use subst on (x+2)/sqrt x,
                                        it will find u = x+2 and complicate the integral */
         )
     return 1;
  if(!ATOMIC(ARG(1,u)) &&
     ispolyin(ARG(1,u),x) &&
     contains(ARG(1,u),'^')       /* a nonlinear poly */
    )
     return 1;
  if(FRACTION(u) &&
     FUNCTOR(ARG(1,u)) == '+' &&
     contains_sqrt(ARG(1,u))
    )
     return 1;  /* pre-empt rationalizedenom */
  return 0;
}
/*____________________________________________________________________*/
static int stopcancel(term t)
/* t is a fraction.  Return 1 if there's a good reason to block
cancellation, because some trivial simplification should be done
first.  This WILL allow  arithmetic to be done on num and denom,
so e.g.   pm/(q(-m))  is not going to cancel m before multiplying,
which looks bad if p,q,m are all large numbers.  But on the whole
we gain more by stopping applications of cancel which do too much
too soon.
   Specifically, if either num or denom is a product containing
a factor which is a product or a negation, return 1.  Else return 0.
*/
{ term u,v;
  int i,j;
  unsigned short f,n;
  if(status(polyvalop)==WELLKNOWN)
      return 0;   /* in that case don't block cancel, get things
                     done as fast as you can. */
  if(!FRACTION(t))
     return 0;    /* assert(0) */
  if(FRACTION(ARG(0,t)) && FRACTION(ARG(1,t)))
     return 1;   /* invert and multiply first */
  for(i=0;i<2;i++)
     { u = ARG(i,t);
       f = FUNCTOR(u);
       if(f == '^' && equals(ARG(0,u),ten) && FUNCTOR(ARG(1,u)) == LOG)
          return 1;
       if(f == '^' && equals(ARG(0,u),eulere) && FUNCTOR(ARG(1,u)) == LN)
          return 1;
       if(f == '^' && FUNCTOR(ARG(1,u)) == LOGB && equals(ARG(0,u),ARG(0,ARG(1,u))))
          return 1;
       if(f == '^' && equals(ARG(0,u),ten) && FUNCTOR(ARG(1,u)) == '*' &&
          contains_at_toplevel(ARG(1,u),LOG)
         )
          return 1;
       if(f == '^' && equals(ARG(0,u),eulere) && FUNCTOR(ARG(1,u)) == '*' &&
          contains_at_toplevel(ARG(1,u),LN)
         )
          return 1;
       if(f == '^' && FUNCTOR(ARG(1,u)) == '*')
          { n = ARITY(ARG(1,u));
            for(j=0;j<n;j++)
               { if(FUNCTOR(ARG(j,ARG(1,u))) == LOGB &&
                    equals(ARG(0,ARG(j,ARG(1,u))), ARG(0,u))
                   )
                    return 1;
               }
          }
       if(f != '*')
          continue;
       n = ARITY(u);
       for(j=0;j<n;j++)
          { v = ARG(j,u);
            if(NEGATIVE(v))
               return 1;
            if(FUNCTOR(v) == '*')
               return 1;
          }
     }
  return 0;
}

/*___________________________________________________________*/
int contains_bound_vars(term t)
/* return 1 if t contains DIFF,INTEGRAL, LIMIT, SUM, or PRODUCT */
{ unsigned short n;
  int i;
  if(ATOMIC(t))
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_bound_vars(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*___________________________________________________________*/
static int contains_fract(term u)
/* u is a sum, power, or product.
Return 1 if u contains fractions that will eventually be
put over a common denom.  This is used to block the
use of cancelgcd on a fraction with u in the num or denom */
{ unsigned short f = FUNCTOR(u);
  unsigned short n = ARITY(u);
  int i;
  if(ATOMIC(u))
     return 0;
  if(f == '^')
     return contains_fract(ARG(0,u));
  if(f == '/')
     return 1;
  for(i=0;i<n;i++)
     { if(contains_fract(ARG(i,u)))
          return 1;
      }
  return 0;
}
/*___________________________________________________________*/
static int contains_deriv(term u, term x)
/* return 1 if u contains a derivative with respect to x */
{ int i;
  unsigned short n;
  if(ATOMIC(u))
     return 0;
  if(FUNCTOR(u) == DIFF && equals(ARG(1,u),x))
     return 1;
  n = ARITY(u);
  for(i=0;i<n;i++)
     { if(contains_deriv(ARG(i,u),x))
          return 1;
     }
  return 0;
}
/*___________________________________________________________*/
static int trigfactor(term t)
/* t is a sum of arity 2 or 3.  Unless each summand is a sin or cosine,
the function will fail, returning 0.  Success will be indicated by
a nonzero value. Determine whether sumofsin, difofsin, sumofcos, difofcos
should be used.  In case of arity 2, return 1,2,3,or 4 to indicate which
of these operators (in the listed order) should be tried.  In case
of arity 3, just return 1.  All four operators will be tried.
The operator itself will decide which of the three args to
work on.
   The following code makes them be tried when the args of the
trig functions are integer multiples of the same symbolic part,
and in case n == 2, both are even or both odd, so fractions won't
be created, and at least one is more than 2, because for sin 2x,
you might as well expand.
  These operations have to be in pre_ops, else trig functions
get expanded (in some topics) in post_ops.  When n is two
you might as well just expand.
*/
{ term a,b,c,p,q,r;
  long ka, kb;
  term na,nb,nc,sa,sb,sc;
  int sign = 1;
  unsigned short fa,fb,fc;
  unsigned short n = ARITY(t);
  assert(FUNCTOR(t) == '+');
  a = ARG(0,t);
  b = ARG(1,t);
  if(n == 3)
     c = ARG(2,t);
  if(NEGATIVE(a))
     { sign = -1;
       a = ARG(0,a);
     }
  if(NEGATIVE(b))
     { sign = sign < 0 ? -2: -1;
       b = ARG(0,b);
     }
  fa = FUNCTOR(a);
  fb = FUNCTOR(b);
  if(fa != SIN && fa != COS)
     return 0;
  if(fb != SIN && fb != COS)
     return 0;
  if(n == 2 && fa != fb)
     return 0;
  p = ARG(0,a);
  q = ARG(0,b);
  if(get_currenttopic() == _trig_factor)
     { /* only require p and q be nonconstant */
       if(constant(p) || constant(q))
          return 0;
       goto out;
     }
  if(n == 3)
     { fc = FUNCTOR(c);
       if(NEGATIVE(c))
          { c = ARG(0,c);
            sign = sign < 0 ? sign-1 : -1;
          }
       if(fc != SIN && fc != COS)
          return 0;
       r = ARG(0,c);
     }
  /* Now, p and q, and r if n==3, must both be integer multiples of the
     same thing. */
  ratpart2(p,&na,&sa);
  if(!INTEGERP(na))
     return 0;
  ratpart2(q,&nb,&sb);
  if(!INTEGERP(nb) || (equals(na,nb) && n == 2))
     return 0;
  if(!equals(sa,sb))
    return 0;
  if(n==3)
     { ratpart2(r,&nc,&sc);
       if(!INTEGERP(nc))
          return 0;
       if(equals(na,nb) && equals(na,nc))
          return 0;  /* all three args equal */
       if(!equals(sa,sc))
          return 0;
       if(equals(na,nc) || equals(nb,nc))
          return 0;  /* all 2 coefficients must be different */
       if(sign == -3)
          return 0;  /* all 3 terms negative */
       return 1;
     }
  if(n == 2 && !SOLVETYPE(get_problemtype()))
     { /* the coefficients must be both even or both odd, so fractions
          won't be created */
       ka = INTDATA(na);
       kb = INTDATA(nb);
       if( (ka + kb) & 1)
          return 0;
       goto out;

     }
  out:
     if(sign == -2)
        return 0;  /* both terms negative */
     if(fa == SIN && sign > 0)
        return 1;  /* sumofsin */
     if(fa == SIN && sign == -1)
        return 2;  /* difofsin */
     if(fb == COS && sign > 0)
        return 3;  /* sumofcos */
     if(fb == COS && sign == -1)
        return 4;  /* difofcos */
     assert(0);
     return 1;
}
/*_______________________________________________________________*/
static int suppress_trig_expansion(term u, term x)
/* u is an integrand, x the variable of integration.
Even though u may contain trig
functions with different arguments, it may be that
cos 2x should not be expanded, because
next sin^2 x will be written in terms of cos 2x and
then the substitution v = 2x will be made.  This
function detects the case in which u contains
only cos (2n)x and sin^2 mx, cos^2 mx so that this
can happen, where 2n and m are specific integers.
  But, consider integral( 1/(1-sin^2 x),x).  Here we
want to wait till 1-sin^2 x is rewritten cos^2 x, we
don't want to write sin^2 x in terms of cos 2x.
Indeed in general we don't want to use these half-angle
formulas in the denominator of an integrand.  Therefore
return 0 if u contains a fraction with a non-constant
denominator.
   Return 0 to suppress trig expansion, 1 not to
suppress it.
*/
{ unsigned short f = FUNCTOR(u);
  unsigned short n;
  int i;
  term v;
  if(ATOMIC(u))
     return equals(u,x) ? 0 : 1;
  if(f == COS)
     { v = ARG(0,u);
       if(FUNCTOR(v) == '*' && ARITY(v) == 2 &&
          INTEGERP(ARG(0,v)) && ISEVEN(ARG(0,v)) &&
          equals(ARG(1,v),x)
         )
          return 1;
       else
          return 0;
     }
  if(f == '^' && (FUNCTOR(ARG(0,u)) == SIN || FUNCTOR(ARG(0,u)) == COS) &&
     INTEGERP(ARG(1,u)) && ISEVEN(ARG(1,u))  /* even exponent */
    )
     { v = ARG(0,ARG(0,u));
       if(equals(x,v))
          return 1;
       if(FUNCTOR(v) == '*' && ARITY(v) == 2 &&
          INTEGERP(ARG(0,v)) && equals(ARG(1,v),x)
         )
          return 1;
       return 0;
     }
  if(f == '+' && ARITY(u) == 2 &&
     FUNCTOR(ARG(0,u)) == '^' && FUNCTOR(ARG(1,u)) == '^' &&
     equals(ARG(1,ARG(0,u)),two) && equals(ARG(1,ARG(1,u)),two)
    )
     { term a,b;
       a = ARG(0,ARG(0,u));
       b = ARG(0,ARG(1,u));
       if(equals(ARG(0,a),ARG(0,b)) &&
          ((FUNCTOR(a)==COS && FUNCTOR(b)==SIN) || (FUNCTOR(b)==COS && FUNCTOR(a)==SIN))
         )
          return 0;  /* integrand is sin^2 + cos^2 , don't expand */
     }
  if(f == '/' && contains(ARG(1,u),FUNCTOR(x)))
     return 0;
  n = ARITY(u);
  for(i=0;i<n;i++)
     { if(!suppress_trig_expansion(ARG(i,u),x))
          return 0;
     }
  return 1;
}

/*___________________________________________________________*/
static int intsub_on_sum(term t,term x)
/* Return 1 if intsub should be tried on the integrand t,
which is assumed to be a sum.  x is the variable of integration.

For example:  if t = sin x cos x + sin^2 x cos x, we want
to use u = sin x on the whole integral, rather than splitting
into two integrals and introducing the same substitution twice.

On the other hand, if t = 1-1/x, we do NOT want to use
u = - 1/x, because it leads to (u^2+1)/u and soon loops,
except for the name of the variables.  It seems reasonable
that if any summand (after stripping off minus signs and
constant denominators) is not a product or quotient,
or if any summand is a rational function,
then intsub shouldn't be used, at least not before intsum.
Even algebraic function:  consider 1/sqrt(x) + 1/sqrt(x-1),
which leads to a mess upon substituting u = sqrt x.
*/

{ unsigned short n = ARITY(t);
  int i;
  term v;
  if(status(intsub) == UNKNOWN && get_whichpass() == 0)
     return 0;
  for(i=0;i<n;i++)
     { v = ARG(i,t);
       if(NEGATIVE(v))
          v = ARG(0,v);
       if(FRACTION(v) && !contains(ARG(1,v),FUNCTOR(x)))
          v = ARG(0,v);
       if(ATOMIC(v))
          return 0;
       if(FUNCTOR(v) != '*' && FUNCTOR(v) != '/')
          return 0;
       if(algebraic_in2(v,x))
          return 0;
     }
  return 1;  /* every summand is a product or quotient, and
                none is a rational function */
}
/*______________________________________________________________________*/
static int logtrig(term u)
/* return 1 if u contains a subterm ln(f(x)), where f is
csc, sec, cot, or tan; or with log instead of ln
*/
{ unsigned short f,n;
  int i;
  if(ATOMIC(u))
     return 0;
  if(FUNCTOR(u) == LN || FUNCTOR(u) == LOG)
     { f = FUNCTOR(ARG(0,u));
       if(f==TAN || f==COT || f==SEC || f==CSC)
          return 1;
       return 0;
     }
  n = ARITY(u);
  for(i=0;i<n;i++)
     { if(logtrig(ARG(i,u)))
          return 1;
     }
  return 0;
}

/*___________________________________________________________________*/

static int contains_power(term t, term x)
/* return 1 if t contains a power of x */
{ unsigned short n;
  int i;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t) == '^' && equals(x,ARG(0,t)))
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
    { if(contains_power(ARG(i,t),x))
         return 1;
    }
  return 0;
}
/*____________________________________________________________________*/
static int bivariate(term t)
/* return 1 if t contains powers of two or more different variables */
{ int nvariables = get_nvariables();
  term *atomlist;
  int i,count;
  if(nvariables < 2)
     return 0;  /* quickly */
  nvariables = variablesin(t,&atomlist);
  if(nvariables < 2)
     return 0;
  count = 0;
  for(i=0;i<nvariables;i++)
     { if(contains_power(t,atomlist[i]))
          ++count;
     }
  if(count < 2)
     return 0;
  return 1;
}

/*______________________________________________________________________*/
static int blockintlinearity(term u, term x)
/* u is an integrand which is a sum.  Return 1 if
there is a good reason not to split the integral into a sum
of integrals.  For example, if the integrand
is tan^2 x + 1,  sin^2 x + cos^2 x, or sec^2 x - tan^2 x.
This does not need to trap cases where integration by
substitution should be used, as intsub_on_sum does that
and is called first.
*/

{ term a,b,c;
  int sign = 1;
  if(FUNCTOR(u) != '+')
     return 0;
  if(ARITY(u) != 2)
     return 0;
  a = ARG(0,u);
  b = ARG(1,u);
  if(NEGATIVE(a) && NEGATIVE(b))
     { a = ARG(0,a);
       b = ARG(0,b);
     }
  if(ONE(a))
     { c = a;
       a = b;
       b = c;
     }
  if(ONE(b))
     { /* check for tan^2 + 1 */
       if(FUNCTOR(a) != '^' || !equals(ARG(1,a),two))
          return 0;
       if(FUNCTOR(ARG(0,a)) == TAN && equals(ARG(0,ARG(0,a)),x))
          return 1;
       /* This way we won't transform integral(tan^2 u + 1,x) to
          integral(sec^2 u,x), unless u is just x. */
       return 0;
     }
  if(NEGATIVE(a))
     { c = a;
       a = b;
       b = c;
     }
  if(NEGATIVE(b))
     { sign = -1;
       b = ARG(0,b);
     }

  if(FUNCTOR(a) != '^' || !equals(ARG(1,a),two))
     return 0;
  if(FUNCTOR(b) != '^' || !equals(ARG(1,b),two))
     return 0;
  a = ARG(0,a);
  b = ARG(0,b);
  if(!equals(ARG(0,a),ARG(0,b)))
     return 0;
  if(sign > 0 && FUNCTOR(a) == SIN && FUNCTOR(b) == COS)
     return 1;
  if(sign > 0 && FUNCTOR(b) == SIN && FUNCTOR(a) == COS)
     return 1;
  if(sign < 0 && FUNCTOR(b) == SEC && FUNCTOR(a) == TAN)
     return 1;
  if(sign < 0 && FUNCTOR(a) == SEC && FUNCTOR(b) == TAN)
     return 1;
  return 0;
}
/*________________________________________________________________*/
static int perfect_square(long x)
/* return nonzero if x is a perfect square, 0 if not */
{ double z = sqrt(x);
  if(fabs(z * z - x) < 0.2)
     return 1;
  return 0;
}

/*________________________________________________________________*/
static int perfect_power(long x, long n)
/* return nonzero if x is a perfect n-th power, 0 if not */
{ double z = pow(x,1/(double) n);
  if(fabs(pow(z,n) - x ) < 0.2)
     return 1;
  return 0;
}
/*_________________________________________________________________*/
static int block_regroupterms(term t)
/* t is a sum.  Return 1 if pushminusin can work on a subterm of t,
else return 0. */
{ unsigned short n = ARITY(t);
  int j;
  term u;
  assert(FUNCTOR(t) == '+');
  for(j=0;j<n;j++)
     { u = ARG(j,t);
       if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == '+')
          return 1;
       if(FUNCTOR(u) == '+' && block_regroupterms(u))
          return 1;
     }
  return 0;
}
/*______________________________________________________________________*/
static int trignegative(term t)
/* return 1 if t contains a trig function with a negative argument */
{ int i;
  unsigned short f,n;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if(TRIGFUNCTOR(f) && NEGATIVE(ARG(0,t)))
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(trignegative(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*______________________________________________________________________*/
static int count_abs(term t)
/* Return the number of non-econstant ABS subterms of t.
   Nested ABS terms will not be counted.
*/
{ unsigned short n;
  int i;
  int count = 0;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t)==ABS)
     return econstant(t) ? 0 : 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     count += count_abs(ARG(i,t));
  return count;
}

/*__________________________________________________________________*/
static int local_contains_trig(term t)
/* return 1 if t contains a trig functor */
/* local copy of the function in polyval.dll, for speed */
{ unsigned short n,f;
  int i;
  if(ATOMIC(t))
     return 0;
  n = ARITY(t);
  f = FUNCTOR(t);
  if(f == SIN || f == COS || f == TAN || f == COT || f == CSC || f == SEC)
     return 1;
  for(i=0;i<n;i++)
     { if(local_contains_trig(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*________________________________________________________________________*/
static int permits_collection(term t)
/* return 1 if t is a sum which permits additive cancellation or
collection, or a product one of whose factors permits collection,
or a power with an integer exponent whose base permits collection.
Otherwise return 0.
*/
{ unsigned short f = FUNCTOR(t);
  unsigned short n = ARITY(t);
  int i;
  term u;
  if(ATOMIC(t))
     return 0;
  if(f == '^')
     { if(INTEGERP(ARG(1,t)))
          return permits_collection(ARG(0,t));
       return 0;
     }
  if(f == '*')
     { for(i=0;i<n;i++)
          { if(permits_collection(ARG(i,t)))
               return 1;
          }
       return 0;
     }
  if(f == '+')
     return collect(t,&u);
     /* collect returns nonzero if something collects or cancels */
  return 0;
}


/*________________________________________________________________________*/

static int contains_big_power(term t)
/* return 1 if t contains a power x^n with n an integer > 50 */
{ unsigned i,n;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t) == '^' && ISINTEGER(ARG(1,t)) && INTDATA(ARG(1,t)) > 50)
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_big_power(ARG(i,t)))
           return 1;
     }
  return 0;
}  

static int stop_cancelgcd(term t)
/* t is the num or denom of a fraction.  If t is a sum that
permits collecting or cancelling of additive terms,
or contains as a summand products of sums that can be multiplied out,
or contains fractions, or contains sums that can be
content_factored, return 1.
   Also, if t can be content_factored or contains a factor that
can be content_factored, return 1, because although cancelgcd will
do it, if it factors both num and denom it can't tell ShowStep
what to select.
   Also,  stop it in case t contains a power x^n with n an integer > 50.
   Otherwise return 0.
*/
{ int i;
  unsigned short n;
  term c,s,u;
  if(ATOMIC(t))
     return 0;
  if(contains_fract(t))
     return 1;
  if(expandable_sum(t))
     return 1;
  if(FUNCTOR(t) == '+')
     { if(permits_collection(t))
          return 1;
       if(!content_factor(t,&c,&s))
          return 1;
       return 0;
     }
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(!content_factor(u,&c,&s))
               return 1;
          }
     }
  if(contains_big_power(t))
     return 1;
  return 0;
}

/*______________________________________________________________________*/
static int stop_differenceofsquares(term t)
/* t is an arity 2 sum.  Return 1 in order to
prevent t from being factored by differenceofsquares.
Example:  don't factor 1-1/x^2 = (1-1/x)(1+1/x), because
this only complicates the problem rather than simplifying it.
Example 2:   x^(2n)- x^(2m), which should be content-factored,
provided n-m is an integer.
Return 0 to proceed with factoring.
*/

{ term u,v,p,q,temp;
  unsigned short f,g;
  if(FUNCTOR(t) != '+' || ARITY(t) != 2)
     return 1;   /*  assert(0)  */
  u = ARG(0,t);
  v = ARG(1,t);
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(NEGATIVE(v))
     v = ARG(0,v);
  f = FUNCTOR(u);
  g = FUNCTOR(v);
  if(f == '^' && g == '^' && equals(ARG(0,u),ARG(0,v)))
     { p = ARG(1,u);
       q = ARG(1,v);
       if(INTEGERP(p) && INTEGERP(q))
          return 1;
       polyval(sum(p,tnegate(q)),&temp);
       if(INTEGERP(temp))
          return 1;
     }
  if(f == '^')
     u = ARG(0,u);
  if(g == '^')
     v = ARG(0,v);
  if(FRACTION(v) && !numerical(ARG(1,v)))
     return 1;
  if(FRACTION(u) && !numerical(ARG(1,u)))
     return 1;
  return 0;
}

/*______________________________________________________________________*/
static int commondenom_in_preops(term t)
/* return 1 if commondenom needs to be applied to t before
the summands are simplified.
   Specifically, if  t has the form  sqrt(u)/a +b/ sqrt u
or some closely related forms, where a doesn't contain a
square root not a factor of b.
   Also, if t is inside a derivative, return 0; never use
common denoms before differentiating.
   Return 0 otherwise.
*/

{ term a,b,cancelled,trash;
  int err;
  if(FUNCTOR(t) != '+')
     return 0;
  if(ARITY(t) > 2)
     return 0;  /* too complicated to worry about */
  if(difflag)
     return 0;  /* don't use common denoms inside derivatives. */
  a = ARG(0,t);
  b = ARG(1,t);
  if(NEGATIVE(a))
     a = ARG(0,a);
  if(NEGATIVE(b))
     b = ARG(0,b);
  if(FRACTION(a) && FRACTION(b))
     { err = cancel(ARG(0,a),ARG(1,b),&cancelled,&trash);
       if(!err && contains(cancelled,SQRT))
          return 1;
       err = cancel(ARG(0,b),ARG(1,a),&cancelled,&trash);
       if(!err && contains(cancelled,SQRT))
          return 1;
       return 0;
     }
  if(FRACTION(b))
     { err = cancel(a,ARG(1,b),&cancelled,&trash);
       if(!err && contains(cancelled,SQRT))
           return 1;
       return 0;
     }
  if(FRACTION(a))
     { err = cancel(b,ARG(1,a),&cancelled,&trash);
       if(!err && contains(cancelled,SQRT))
           return 1;
       return 0;
     }
  return 0;
}
/*_________________________________________________________________________*/
static int nearly_done(term t)
/* t is an equation.  Return 1 if it's an identity within a very few
simple steps of completion.  Then it looks silly to substitute.
Return 0 otherwise.
*/
{ term u,v,x,temp,num,denom;
  unsigned short f,g,h1,h2;
  if(FUNCTOR(t) != '=')
     return 0;
  u = ARG(0,t);
  v = ARG(1,t);
  if(NEGATIVE(u) && NEGATIVE(v))
     { u = ARG(0,u);
       v = ARG(0,v);
     }
  f = FUNCTOR(u);
  g = FUNCTOR(v);
  if(TRIGFUNCTOR(g) && !TRIGFUNCTOR(f))  /* then swap */
      { temp = u;
        u = v;
        v = temp;
        f = FUNCTOR(u);
        g = FUNCTOR(v);
      }
  if(!TRIGFUNCTOR(f))
      return 0;
  x = ARG(0,u);
  if(g == '/')
     { num = ARG(0,v);
       denom = ARG(1,v);
       h1 = FUNCTOR(num);
       h2 = FUNCTOR(denom);
       if(!ONE(num) && !TRIGFUNCTOR(h1) || !TRIGFUNCTOR(h2))
          return 0;
       if(!equals(ARG(0,num),x) || !equals(ARG(0,denom),x))
          return 0;
       switch(f)
          { case TAN:
               if(h1 == SIN && h2 == COS)
                  return 1;
               if(ONE(num) && h2 == COT)
                  return 1;
               return 0;
            case COT:
               if(h1 == COS && h2 == SIN)
                   return 1;
               if(ONE(num) && h2 == TAN)
                   return 1;
               return 0;
            case SEC:
               if(ONE(num) && h2 == COS)
                  return 1;
               return 0;
            case CSC:
               if(ONE(num) && h2 == SIN)
                  return 1;
               return 0;
            case SIN:
               if(ONE(num) && h2 == CSC)
                  return 1;
               return 0;
            case COS:
               if(ONE(num) && h2 == SEC)
                  return 1;
               return 0;
          }
     }
  return 0;
}
/*_________________________________________________________________________*/
static int sumoflogs(term t)
/* return 1 if t is a sum of log terms, 0 if not */
{ unsigned short n,g;
  term u;
  int i,count=0;
  if(FUNCTOR(t) != '+')
    return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       g = FUNCTOR(u);
       if(g == LN || g == LOG || g == LOGB)
          ++count;
     }
 if(count == n)
    return 1;
 return 0;
}
/*_________________________________________________________________________*/
static int stop_maxsub(term u)
/* return 1 to block the use of maximalsub on u*/
{ unsigned short f;
  term c,s;
  int currenttopic = get_currenttopic();
  int problemtype = get_problemtype();
  if(!SOLVETYPE(problemtype) && CALCULUS_TOPIC(currenttopic))
     return 1;  /* e.g. when sec(arctan(sqrt 5 u)) has arisen
                   as part of an answer to an integral, don't set
                   v = arctan(sqrt 5 u) while simplifying. */
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(ATOMIC(u))
     return 1;
  f = FUNCTOR(u);
  if (FRACTION(u) && !econstant(denom(u)) && noxious(denom(u)))
     return 1;
  if(
     FUNCTOR(u) == '+' && ARITY(u) == 2 &&
     (
       (SIGNEDFRACTION(ARG(1,u)) && noxious(denom(ARG(1,u)))) ||
       (SIGNEDFRACTION(ARG(0,u)) && noxious(denom(ARG(0,u))))
     )
    )
     return 1;
  if(FUNCTOR(u) == '=' && nearly_done(u))
     return 1;
  if(FUNCTOR(u) == '+' && contains(u,'/') && immediate_comdenom(u))
     return 1;
  if(different_sqrts(u))
     return 1;
  if(f == '*' &&  special_difofsquares(u))
     return 1;
  if(f == '/' &&
     (special_difofsquares(ARG(1,u)) || special_difofsquares(ARG(0,u)))
    )
     return 1;
  if(f == '+' && sumoflogs(u))
      /* example, log(sqrt(x) + 1) + log(sqrt(x)-1) */
      /* stop it on a sum of logs.  This may be overzealous, we'll see. */
     return 1;
  if(f == '*')
    { ratpart2(u,&c,&s);
      if(FUNCTOR(s) == '+' && sumoflogs(s))
         return 1;
    }
  return 0;
}

/*_________________________________________________________________*/
int almost_algebraic(term t)
/* return 1 if t has the form  a/c +/- sqrt(b)/d  for
integers a,b,c,d.  (We want to trap these in preops and
simplify them immediately to algebraic number standard form,
to prevent wasting steps with addfractions and commondenom,
contenfactor, etc.)
   Also works on x + a/c +/- sqrt(b)/c
since such expressions are produced by the quadratic formula.
   Otherwise return 0.
*/

{ term a,b,c,d,u,v;
  if(FUNCTOR(t) != '+')
     return 0;
  if(ARITY(t) > 3)
     return 0;
  if(ARITY(t) == 2)
    { u = ARG(0,t);
      v = ARG(1,t);
    }
  else if(ARITY(t) == 3 && ISATOM(ARG(0,t)))
    { u = ARG(1,t);
      v = ARG(2,t);
    }
  else
     return 0;
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(NEGATIVE(v))
     v = ARG(0,v);
  if(!FRACTION(u) || !FRACTION(v))
     return 0;
  a = ARG(0,u);
  c = ARG(1,u);
  b = ARG(0,v);
  d = ARG(1,v);
  if(FUNCTOR(b) != SQRT)
     return 0;
  if(!INTEGERP(ARG(0,b)))
     return 0;
  if(!INTEGERP(a) || !INTEGERP(c) || !INTEGERP(d))
     return 0;
  return 1;
}

/*__________________________________________________________________*/
int sqrtcomdenom(term t)
/* called from stopsub in autoeqn.c to prevent using substitutions on examples
like (3/sqrt(x)- 9sqrt(x))^2 = 6x-2, in which common denoms should be used
instead of substitution.  Return 1 if after stripping away minus signs and
integer exponents from t we are left with a sum on which commondenom_in_preops
returns 1. */
{ term u = t;
  while(NEGATIVE(u) ||
        (FUNCTOR(u) == '^' && isinteger(ARG(1,u)))
       )
     u = ARG(0,u);
  return commondenom_in_preops(u);
}

/*___________________________________________________________________*/
static int trigproducts(term t)
/* t is a sum of arity 2.
Return nonzero if sinsumrev, sindifrev, cossumrev, or cosdifrev
will work leaving a sin or cos of a non-sum.
Example:  sin(x-a)cos(x+a) + cos(x-a)sin(x+a) = sin(2x)
Return 1,2,3,or 4 to tell which of these operators (in the listed
order) should be used.  Return 0 if none of them will work
leaving a sin or cos of a non-sum.
*/
{ unsigned short n = ARITY(t);
  term u,v,a,b,c,d;
  unsigned short fa,fb,fc,fd;
  int sign = 1;
  char buffer[DIMREASONBUFFER];
  term w;
  if(FUNCTOR(t) != '+' || n != 2)
     return 0;
  u = ARG(0,t);
  v = ARG(1,t);
  if(NEGATIVE(u))
     { u = ARG(0,u);
       sign *= -1;
     }
  if(NEGATIVE(v))
     { v = ARG(0,v);
       sign *= -1;
     }
  if(FUNCTOR(u) != '*' || FUNCTOR(v) != '*')
     return 0;
  if(ARITY(u) != 2 || ARITY(v) != 2)
     return 0; /* giving up on 2 sin(x-a) cos(x+a) + 2 cos(x-a) sin(x+a) = 2 sin 2x,
                  unfortunately, but this will come up very rarely. */
  a = ARG(0,u);
  b = ARG(1,u);
  c = ARG(0,v);
  d = ARG(1,v);
  fa = FUNCTOR(a);
  fb = FUNCTOR(b);
  fc = FUNCTOR(c);
  fd = FUNCTOR(d);
  if(fa != SIN && fa != COS)
     return 0;
  if(fb != SIN && fb != COS)
     return 0;
  if(fc != SIN && fc != COS)
     return 0;
  if(fd != SIN && fd != COS)
     return 0;
  if(
      (fa == SIN && fb == SIN && fc == COS && fd == COS) ||
      (fa == COS && fb == COS && fc == SIN && fd == SIN)
    )
     { if(sign == 1 && !cosdifrev(t,zero,&w,buffer) && FUNCTOR(ARG(0,w)) != '+')
          return 4;
       if(sign == -1 && !cossumrev(t,zero,&w,buffer) && FUNCTOR(ARG(0,w)) != '+')
          return 3;
     }
  if(fa == fb || fc == fd)
     return 0;
  if(sign == 1 && !sinsumrev(t,zero,&w,buffer) && FUNCTOR(ARG(0,w)) != '+')
     return 1;
  if(sign == -1 && !sindifrev(t,zero,&w,buffer) && FUNCTOR(ARG(0,w)) != '+')
     return 2;
  return 0;
}

/*__________________________________________________________________*/
static int trigargsgcd(term t, term *gcd)
/* return 0 if there is a non-trivial gcd of the args of all the
trig functions in t and the initial value of *gcd.  (So initially,
it will be called with *gcd = zero, and then called recursively with
other arguments.)
 For example, if t is a function of sin (8x) and trig functions of 2x,
and *gcd is initially zero, return 0.  But DO NOT count fractional gcds,
e.g. on sin^4(x/2) + cos^4(x/2), return 1.  Put the gcd of the trig args
and the initial *gcd into *gcd if 0 is returned.  If 1 is returned,
*gcd can be garbage. If there are no trig functions in t, return 2.
*/
{ unsigned short n,f;
  int i,err,retval;
  term s;
  if(ATOMIC(t))
     return 2;
  f = FUNCTOR(t);
  if(TRIGFUNCTOR(f))
     { polygcd(ARG(0,t),*gcd,&s);
       if(ONE(s))
          return 1;
       *gcd = s;
       return 0;
     }
  n = ARITY(t);
  retval = 2;
  for(i=0;i<n;i++)
     { err = trigargsgcd(ARG(i,t),gcd);
       if(err == 1 || ONE(*gcd))
          return 1;
       if(err == 0)
          retval = 0;
     }
  if(ONE(*gcd))
     return 1;
  return retval;
}
/*__________________________________________________________________*/
static int trigargsgcd1(term t)
/* return 0 if there is a non-trivial gcd of the args of all the
trig functions in t, and this gcd either has no fractional part or
the denominator of the fractional part is not even.
   For example, if t is a function of sin (8x) and
trig functions of 2x, return 0.  But DO NOT count fractional gcds with
even denominators, e.g. on sin^4(x/2) + cos^4(x/2), return 1.
*/
{ term temp = zero;
  term c,s;
  int err = trigargsgcd(t,&temp);
  if(err)
     return 1;
  if(ISATOM(temp))
     return 0;   /*  e.g. t may involve cos(x/2) and sin x, so temp is x */ 
  if(FRACTION(temp) && iseven(ARG(1,temp)))
     return 1;
  if(FUNCTOR(temp) == '*')
     { ratpart2(temp,&c,&s);
       if(FRACTION(c) && iseven(ARG(1,c)))
          return 1;
     }
  return 0;
}
/*_________________________________________________________*/
static unsigned short tpf_aux(term t, unsigned short a, unsigned short b)
/* t is an equation.  If one side is an even power of a term with functor b,
and the other side doesn't contain b, then return b.
   Otherwise, if b appears to an odd power, return a,
and if a appears to an odd power, return b, and if neither appears to an odd
power return a, unless t doesn't contain b, in which case return b.
*/
{ int i,aflag,bflag;
  term u;
  if(ARITY(t) != 2)
     return a;
  for(i=0;i<2;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) == '^' &&
          iseven(ARG(1,u)) &&
          FUNCTOR(ARG(0,u)) == b &&
          !contains(ARG(i ? 0 : 1,t),b)
         )
           return b;
     }
  bflag = contains_odd_power(t,b);
  aflag = contains_odd_power(t,a);
  if(bflag)
     return a;
  if(aflag)
    return b;
  if(!contains(t,b))
    return b;
  return a;
}

/* ___________________________________________________________________*/
int algebraic_identity(term t)
/* Return 1 if t is an equation whose two sides polyval to the
same term.  Return 0 otherwise.
*/
{ term u,v;
  int saveit = get_polyvalfactorflag();
  set_polyvalfactorflag(1);
  if(FUNCTOR(t) != '=')
     return 0;
  polyval(ARG(0,t),&u);
  polyval(ARG(1,t),&v);
  set_polyvalfactorflag(saveit);
  if(equals(u,v))
    return 1;
  return 0;
}

/*__________________________________________________________________*/
int contains_power_of_sum(term t)
/* return 1 if t contains a low integer power of a sum, 0 if not. */
{ unsigned short n;
  int i;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t) == '^' && ISINTEGER(ARG(1,t)) &&
     FUNCTOR(ARG(0,t)) == '+' && INTDATA(ARG(1,t)) <= 10
    )
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_power_of_sum(ARG(i,t)))
          return 1;
     }
  return 0;
}

/*____________________________________________________________________*/
static unsigned short twologs(term t)
/* return nonzero if t is a sum containing two logs, possibly multiplied
by an integer;  0 if not. The nonzero
return value is LN, LOG, or LOGB, whichever was found.
*/
{ int k;
  unsigned short n,f,g;
  term u;
  if(FUNCTOR(t) != '+')
     return 0;
  n = ARITY(t);
  f = 0;
  for(k=0;k<n;k++)
     { u = ARG(k,t);
       if(NEGATIVE(u))
          u = ARG(0,u);
       if(FUNCTOR(u) == '*' && ARITY(u) == 2 && INTEGERP(ARG(0,u)))
          u = ARG(1,u);
       g = FUNCTOR(u);
       if(g == LOG || g == LN)
          { if(f && g == f)
               return g;
            else
               f = g;
          }
       else if( g == LOGB)
          { if(f && g == f)
               return g;
            else
              f = g;
          }
       else
          continue;
     }
  return 0;
}

/*_________________________________________________________*/
static int forced_logcollect(unsigned short f, term t)
/* f is LN, LOG, or LOGB.  t is a sum containing two or more summands
with functor f, or an integer times a term with functor f.
If two of these summands (possibly after discarding the initial integer)
have the form  f(a) + f(b/a)
or the form f(ab)-f(a), including numerical cases like ln 6 - ln 2,
return 1.   In general, if the result of collecting logs would permit
a cancel or cancelgcd operation, return 1.
   Also, log(sqrt(x)+2) + log(sqrt(x)-2)  should be collected.  But
log(x-1) + log(x+1) should not be, at least it's not forced by this function.
  Otherwise return 0.
*/

{ int i,j,err;
  unsigned short n = ARITY(t);
  term a,b,u,v,p,q;
  int signu, signv;
  assert(FUNCTOR(t) == '+');
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(NEGATIVE(u))
          { signu = -1;
            u = ARG(0,u);
          }
       else
          signu = 1;
       if(FUNCTOR(u) == '*' && ARITY(u) == 2 && INTEGERP(ARG(0,u)))
          u = ARG(1,u);
       if(FUNCTOR(u) != f)
          continue;
       for(j=i+1;j<n;j++)
          { v = ARG(j,t);
            if(NEGATIVE(v))
               { signv = -1;
                 v = ARG(0,v);
               }
            else
               signv = 1;
            if(FUNCTOR(v) == '*' && ARITY(v) == 2 && INTEGERP(ARG(0,v)))
               v = ARG(1,v);
            if(FUNCTOR(v) != f)
               continue;
            if(f == LOGB && !equals(ARG(0,v),ARG(0,u)))
               continue;
            a = ARG(f == LOGB ? 1: 0,u);
            b = ARG(f == LOGB ? 1: 0,v);
            if(signu != signv)
               { if(!FRACTION(a) && !FRACTION(b))  /* ln ac - ln c */
                    { err = cancel(a,b,&p,&q);
                      if(!err)
                         return 1;
                      err = cancelgcd_aux(a,b,&p,&q);
                      if(!err)
                         return 1;
                    }
                 else if(FRACTION(a) && !FRACTION(b))
                    { /* ln(b/a) - ln b  */
                      err = cancel(ARG(0,a),b,&p,&q);
                      if(!err)
                         return 1;
                      err = cancelgcd_aux(ARG(0,a),b,&p,&q);
                      if(!err)
                         return 1;
                    }
                 else if(FRACTION(b) && !FRACTION(a))
                    { err = cancel(ARG(0,b),a,&p,&q);
                      if(!err)
                         return 1;
                      err = cancelgcd_aux(ARG(0,b),a,&p,&q);
                      if(!err)
                         return 1;
                    }
                 else /* both fractions */
                    { err = cancel(product(ARG(0,a),ARG(0,b)),product(ARG(1,a),ARG(1,b)),&p,&q);
                      if(!err)
                         return 1;
                      err = cancelgcd_aux(ARG(0,a),ARG(0,b),&p,&q);
                      if(!err)
                         return 1;
                    }
               }
            else  /* same sign */
               { if(FRACTION(b) && !FRACTION(a))  /* ln a + ln(c/a) */
                    { err = cancel(a,ARG(1,b),&p,&q);
                      if(!err)
                         return 1;
                      err = cancelgcd_aux(a,ARG(1,b),&p,&q);
                      if(!err)
                         return 1;
                    }
                 else if(FRACTION(a) && !FRACTION(b))
                    { err = cancel(b,ARG(1,a),&p,&q);
                      if(!err)
                        return 1;
                      err = cancelgcd_aux(b,ARG(1,a),&p,&q);
                      if(!err)
                         return 1;
                    }
                 else if(FRACTION(a) && FRACTION(b))
                    { err = cancel(ARG(0,a),ARG(1,b),&p,&q);
                      if(!err)
                         return 1;
                      err = cancel(ARG(0,b),ARG(1,a),&p,&q);
                      if(!err)
                         return 1;
                      err = cancelgcd_aux(ARG(0,a),ARG(1,b),&p,&q);
                      if(!err)
                         return 1;
                      err = cancelgcd_aux(ARG(0,b),ARG(1,a),&p,&q);
                      if(!err)
                         return 1;

                    }
                 else if(FUNCTOR(a) == '+' && FUNCTOR(b) == '+' &&
                         contains(a,SQRT) && contains(b,SQRT)
                        )
                    { term temp = product(a,b);
                      char buffer[DIMREASONBUFFER];
                      term w;
                      int err = difofsquares(temp,zero,&w,buffer);
                      RELEASE(temp);
                      return !err;
                    }
               }
          }
     }
  return 0;
}
/*__________________________________________________________________________*/
static int contains_odd_power(term t, unsigned short f)
/* return 1 if t contains a subterm with functor f, to an odd
power or not to a power (i.e. power 1).  Nested occurrences of f
will not be counted, and occurrences inside functors other than
those used in polynomials will not be counted. */

{ int i;
  unsigned short n,g;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t) == '^' && FUNCTOR(ARG(0,t)) == f)
     { return isodd(ARG(1,t)) ? 1 : 0;
     }
  if(FUNCTOR(t) == f)
     return 1;
  n = ARITY(t);
  g = FUNCTOR(t);
  if(g != '-' && !INEQUALITY(g) && g != '*' && g != '+' && g != '^')
     return 0;
  for(i=0;i<n;i++)
     { if(contains_odd_power(ARG(i,t),f))
          return 1;
     }
  return 0;
}
/*__________________________________________________________________________*/
static int contains_even_power(term t, unsigned short f)
/* return 1 if t contains a subterm with functor f, to an even
positive power. Nested occurrences of f
will not be counted, and occurrences inside functors other than
those used in polynomials will not be counted. */

{ int i;
  unsigned short n,g;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t) == '^' && FUNCTOR(ARG(0,t)) == f)
     { return iseven(ARG(1,t)) ? 1 : 0;
     }
  if(FUNCTOR(t) == f)
     return 0;
  n = ARITY(t);
  g = FUNCTOR(t);
  if(g != '-' && !INEQUALITY(g) && g != '*' && g != '+' && g != '^')
     return 0;
  for(i=0;i<n;i++)
     { if(contains_even_power(ARG(i,t),f))
          return 1;
     }
  return 0;
}
/*________________________________________________________________________*/
int stop_orderterms(term t)
/* Return 1 if t, the term at the end of the current path,
is in a product in a sum, so the product will be multiplied out by 'expand'
anyway.  Don't waste time ordering the terms.
  Also return 1 if t is the arg of a ROOT or SQRT and does not contain
a power.  There's no point in changing sqrt(x+h) to sqrt(h+x).
  Also return 1 if t is an integrand.  Intlinear will be applied,
no point in ordering the sum.  Also if the sum contains an integral.
  Also return 1 if t is one side of an equation in a set of linear
equations.
  Also when solving complex equations, use polynomial order or complexform instead.
*/
{ unsigned short const *path = get_path();
  int pathlength = get_pathlength();
  int i, sumflag=0, productflag=0;
  unsigned short f = FUNCTOR(t);
  int problemtype = get_problemtype();
  int currenttopic = get_currenttopic();
  term u;
  if(get_complex() && iscomplex(t) &&
     (problemtype == SOLVE_EQUATION ||
      currenttopic == _complex_quadratics ||
      currenttopic == _complex_cubics
     )
    )
     return 1;   /* use writeaspoly instead, so we get ix^2 + 1 instead of 1 + x^2 i */
  if(pathlength == 0 && INEQUALITY(f))
     { for(i=0;i<2;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '+' && expandable_sum(u))
               return 1;
          }
       return 0;
     }
  if(pathlength & 1)
     --pathlength;  /* in postops, delete the functor of the current sum */
  if(pathlength >= 2 &&
     (path[pathlength-2] == INTEGRAL || path[pathlength-2] == DIFF)
    )
     return 1;
  if(pathlength >= 2 &&
     (path[pathlength-2] == SQRT  || path[pathlength-2] == ROOT) &&
     !contains(t,'^')
    )
     return 1;
  if(pathlength >= 2 &&
     (path[pathlength-2] == INTEGRAL ||
      path[pathlength-2] == DIFF ||
      path[pathlength-2] == LIMIT
     )
    )
     return 1;
  if(contains(t,INTEGRAL) || contains(t,DIFF) || contains(t,LIMIT))
     return 1;  /* wait till the calculus is done before ordering terms */
  if(pathlength >= 4 && path[pathlength-4] == INTEGRAL &&
     path[pathlength-3] == 1 &&
     path[pathlength-2] == '/' &&
     path[pathlength-1] == 1
    )
     return 1;  /* don't reorder terms in the numerator of an integrand */
  if(problemtype == LINEAR_EQUATIONS &&
     pathlength >= 2 &&
     path[pathlength-2] == '='
    )
     return 1;  /* don't reorder terms in linear equations because
                   lineupvars will be called soon and will take care of it. */
  for(i=0;i<pathlength; i += 2)
     { if(path[i] == '+' && !sumflag)
          { sumflag = 1;
            continue;
          }
       if(sumflag &&
          (
            (path[i] == '^' && path[i+1] == 1) ||
            path[i] == '+' ||
            path[i] == '-'
          )
         )
          continue;
       if(sumflag && path[i] == '*')
          { productflag = 1;
            continue;
          }
       if(productflag == 1 && path[i] == '^' && path[i+1] == 1)
          continue;
       sumflag = productflag = 0;
    }
  return productflag;
}


/*________________________________________________________________________*/
int stop_orderfactors(term t)
/* Return 1 if t, the term at the end of the current path,
is a product which contains a sum, and there is a '+' on
the path to t, so eventually it will be multiplied out.
   Also return 1 if the parent is DIFF or INTEGRAL or SUM or PRODUCT
Don't waste time reordering the factors.
   Also return 1 on ix^2 in problemtype SOLVE_EQUATION
*/
{ unsigned short const *path = get_path();
  int pathlength = get_pathlength();
  int i;
  unsigned short f = FUNCTOR(t);
  if(f != '*')
     return 0;
  if(ORDERED(t))
     return 1;
  if(get_complex() &&
     iscomplex(t) && !constant(t) &&
     get_problemtype() == SOLVE_EQUATION
    )
     return 1;
  if(pathlength < 2)
     return 0;
  if(pathlength >= 2 &&
     (path[pathlength-2] == INTEGRAL || path[pathlength-2] == DIFF ||
      path[pathlength-2] == SUM || path[pathlength-2] == PRODUCT
     )
    )
     return 1;
  if(!expandable(t))
     return 0;
  if(pathlength & 1)
     --pathlength;  /* in postops, delete the functor of the current sum */
  for(i=0;i<pathlength; i += 2)
     { if(path[i] == '+')
          return 1;
     }
  return 0;
}

/*________________________________________________________________________*/
static int contains_complex_exponentials(term t)
/* return 1 if t contains e^complex, 0 if not */
{ unsigned short n;
  int i;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t)== '^' && equals(ARG(0,t),eulere) && iscomplex(ARG(1,t)))
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_complex_exponentials(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*________________________________________________________________________*/
static int stoplogofpower(term u)
/* u is a power.  Return 1 if it has one of the forms a^(log(a,b)),
e^ln(b), 10^log(b), or the same with other factors in the exponents */
{ char buffer[DIMREASONBUFFER];
  term w;
  if(!logbinexponent(u,zero,&w,buffer))
     return 1;
  if(!logbinexponent2(u,zero,&w,buffer))
     return 1;
  if(!lninexponent(u,zero,&w,buffer))
     return 1;
  if(!lninexponent2(u,zero,&w,buffer))
     return 1;
  if(!loginexponent(u,zero,&w,buffer))
     return 1;
  if(!loginexponent2(u,zero,&w,buffer))
     return 1;
  return 0;
}
/*_______________________________________________________________________*/
static int trigalg_same_aux(term u, term x, term *arg)
/* return 1 if u is built up algebraically from trig functions of
*arg, if *arg is not ILLEGAL; if *arg is ILLEGAL, fill it in
as the arg of the first trig function encountered as a subterm of u.
But if that arg is just x itself, fail.  Return 0 for failure.
*/
{ unsigned short n;
  int i;
  unsigned short f = FUNCTOR(u);
  if(TRIGFUNCTOR(f) && contains(ARG(0,u),FUNCTOR(x)))
     { if(equals(ARG(0,u),x))
          return 0;
       if(FUNCTOR(*arg) != ILLEGAL && !equals(ARG(0,u),*arg))
          return 0;
       if(FUNCTOR(*arg) == ILLEGAL)
          *arg = ARG(0,u);
       return 1;
     }
  if(ATOMIC(u))
     return 1;
  n = ARITY(u);
  for(i=0;i<n;i++)
     { if(!trigalg_same_aux(ARG(i,u),x,arg))
          return 0;
     }
  return 1;
}

/*_______________________________________________________________________*/
static int trigalg_same(term u, term x)
/* return 1 if u is built up algebraically from trig functions of
the same argument, not just x itself. Return 0 otherwise.
*/
{ term arg;
  int rval;
  SETFUNCTOR(arg,ILLEGAL,0);
  rval = trigalg_same_aux(u,x,&arg);
  if(rval == 0)
     return 0;
  if(FUNCTOR(arg) == ILLEGAL)
     return 0;  /* no trig function found */
  if(equals(arg,x))
     return 0;  /* per specs */
  return 1;
}
/*___________________________________________________________________*/
static int exponential_factor(term t,term x)
/* return 1 if t is a product containing a factor e^u where u contains x,
but is not linear in x,
or if t is a fraction whose num or denom contains such a factor; or if
the first arg is c^u(x), as in 2^x/(1+2^x)^2  */
{ unsigned short n;
  int i;
  term u;
  if(FRACTION(t))
     return exponential_factor(ARG(0,t),x) || exponential_factor(ARG(1,t),x);
  if(FUNCTOR(t) == '^' && !contains(ARG(0,t),FUNCTOR(x)) && contains(ARG(1,t),FUNCTOR(x)))
     return 1;
  if(FUNCTOR(t) != '*')
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) == '^' &&
          !contains(ARG(0,u),FUNCTOR(x)) &&
          contains(ARG(1,u),FUNCTOR(x)) &&
          !is_linear_in(ARG(1,u),x)
         )
          return 1;
     }
  return 0;
}
/*___________________________________________________________________*/
static int stop_arith(term t)
/* if t contains more than one term of the forms 0+x,  0*u, 1*u
where u is not numerical, return nonzero.  In general, return the
number of such subterms.  (This is used to prevent using 'arithmetic'
on such terms--polyvalop will be used instead.)
*/
{ unsigned short n,f;
  int i, count;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  n = ARITY(t);
  switch(f)
     { case '+':
          count = 0;
          for(i=0;i<n;i++)
             { if(ZERO(ARG(i,t)))
                  ++count;
               count += stop_arith(ARG(i,t));
             }
          return count;
       case '*':
          count = 0;
          for(i=0;i<n;i++)
             { if(ZERO(ARG(i,t)) || ONE(ARG(i,t)))
                  ++count;
               count += stop_arith(ARG(i,t));
             }
          return count;
     }
  count = 0;
  for(i=0;i<n;i++)
     count += stop_arith(ARG(i,t));
  return count;
}

/*____________________________________________________________*/
static int obvious_trig(term t)
/* return 1 if t contains a sum of the form cos^2 x + sin^2 x,
0 otherwise
*/
{ unsigned short i,n;
  int err;
  term lhs,a,temp;
  if(ATOMIC(t))
     return 0;
  n = ARITY(t);
  if(FUNCTOR(t) == '+')
     { lhs = sum(make_power(sin1(var0),two),make_power(cos1(var0),two));
       err = match(t,lhs,one,&a,&temp);   /* instantiate a and temp */
       if(!err)
          return 1;
     }
  for(i=0;i<n;i++)
     { if(obvious_trig(ARG(i,t)))
          return 1;
     }
  return 0;
}

/*____________________________________________________________*/
static int complex_addfractions_conditions(term t)
/* t is a sum of 2 fractions, and t contains complexi.
Should we use addfractions?
Return 1 if so, 0 if not
*/
{ term u = ARG(0,t);
  term v = ARG(1,t);
  term num1,num2, den1, den2;
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(NEGATIVE(v))
     v = ARG(0,v);
  if(!FRACTION(u) || !FRACTION(v))
     return 0;  /* assert(0) */
  num1 = ARG(0,u);
  num2 = ARG(0,v);
  den1 = ARG(1,u);
  den2 = ARG(1,v);
  if(!equals(den1,den2))
     return 0;  /* addfractions won't work anyway */
  if(iscomplex(den1))
     { if(mvpoly(num1) && mvpoly(num2))
           return 1;
       return 0;
     }
  if(iscomplex(num1) && iscomplex(num2))
     return 1;
  return 0;
  /* don't add fractions in sqrt(3)/2^(3/4) + i/2^(3/4)  */
}
/*___________________________________________________________*/
static int common_factor(term u, term v)
/* return 1 if u and v have a common factor that 
might be cancelled out in the identity u = v.  
Do not check if the conditions for cancellation 
are actually satisfied; the operation will do that.
*/
{ int err;
  term a,b;
  while(FRACTION(u) || NEGATIVE(u))
     u = ARG(0,u);
  while(FRACTION(v) || NEGATIVE(v))
     v = ARG(0,v);
  err = cancel(u,v,&a,&b);
  return !err;
}

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