Sindbad~EG File Manager

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

/* automode solving of a single (linear or nonlinear) equation for MathXpert */
/* M. Beeson
Original date 6.3.91
2.19.99  modified
12.26.99 added 'collected(t) > 1' at line 245
1.9.00 modified really_contains_monomially.
1.12.00 blocked polyvalop on _complex_quadratics
2.25.00 added containsPminusP and code that calls it, and related line stopsub != 2
3.4.00 added code to inhibit_transfer at the end
8.9.07 modified conditions for polyvalop so it's not used on _complex_roots unless pathlength > 2
8.26.11 added LOGB at line 119
5.6.13  include stdef.h
6.5.13 modified stop_alltoleft and inhibit_transfer so it stops adding and subtracting
        on TESTCONVERGENCE when there's a series in the inequality
9.26.14 removed unused function postpone_polyval
1.4.25  added mul_eqn to pre_equation for IMPLICIT_DIFF problems.
1.22.25 added the dated line to prevent multiplying by 9 when we have e.g. (x-(1/3))^2 = 7/9
*/

#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "mpdoc.h"
#include "tdefn.h"
#include "checkarg.h"  /* operator typedef   */
#include "ops.h"
#include "trig.h"
#include "prover.h"    /* noccurs            */
#include "probtype.h"  /* needed by eqn.h    */
#include "eqn.h"       /* derivative_subterm */
#include "trigtran.h"  /* assess_trig        */
#include "algaux.h"    /* twoparts           */
#include "symbols.h"
#include "cflags.h"    /* set_substitutionflag */
#include "autoeqn.h"
#include "autosum.h"   /* special_difofsquares, immediate_comdenom */
#include "automode.h"  /* block_squareeqn2     */
#include "pvalaux.h"   /* iseven               */
#include "polynoms.h"
#include "fraction.h"  /* denom                */
#include "pathtail.h"  /* set_pathtail         */
#include "calc.h"      /* polyvalop            */
#include "cancel.h"
#include "autosimp.h"  /* get_pathlength       */
#include "domain.h"    /* contains_defined_variables */
#include "trigpoly.h"  /* trigpoly2            */
#include "solvelin.h"  /* derivative_subterm   */

static int must_square(term);
static int odd_trig_power(term);
static int block_crossmultiply(term t);
static int block_squareeqn(term t);
static int block_squareeqn3(term t);
static int contains_root_of_power(term t);
static unsigned short contains_sqrt4(term a);
static int contains_halfpower(term t);
static int contains_root(term t,term x);
static int stop_sub(term u, term v);
static int really_contains_monomially(term t, unsigned short f);
static int fcount(term t, unsigned short f);
static int containsPminusP(term t);
/*______________________________________________________________*/
void pre_equation(term t, actualop *o, int *nops)
/*  Generate a list of operators to be tried in pre_ops when
solving equations.  This is called by ssolve, and by pre_ops
when SOLVETYPE(problemtype).
Put the operators to be used in o[0], o[1],... and return
the number of operators in *nops.  t is an equation.
*/
{ term u,v,w,trash;
  int j;
  int i=0;
  int problemtype = get_problemtype();
  char buffer[DIMREASONBUFFER];
  int stopsub,mustsq;
  unsigned short g;
  term x = get_eigenvariable();
  u = ARG(0,t);
  v = ARG(1,t);
  // in IMPLICIT_DIFF,  we need  muleqn  on the problem (xy+y^3)/(1+x) = 1
  // before the equation is differentiated,  but if we put muleqn in pre_ops
  // (that is, here), it leads to multiplying by 2 again and again
  // when there's a 2 in a denominator inside a sum.   Hence we use it
  // only when the left side is a fraction.
  if(problemtype == IMPLICIT_DIFF &&
     !contains(t,DIFF) && !contains(t,PR) &&
       // only do it before the equation has been differentiated.
     FRACTION(u) &&! contains(v,FUNCTOR(x))
    )
     { o[i] = muleqn; ++i;
     }
  if(equals(u,x) && !contains(v,FUNCTOR(x)))
     { if(get_complex() && get_pathlength() == 0 &&
          contains_existentials(t) &&
          !contains_defined_variables(t)
         )
          { o[i] = explicitparams; ++i;
          }
       *nops = i;  /* already solved.  Later solve_equation will try checkroot */
       return;
     }
  if(status(solvelinear) >= KNOWN)
     { o[i] = solvelinear; ++i;
     }
  o[i] = rejecteqn; ++i;   /* try to catch unsolvable equations as
                              soon as possible! in particular before
                              making substitutions or changing roots
                              to fractional exponents */
  if(FUNCTOR(u) == FUNCTOR(v))
     { g = FUNCTOR(u);
       if(equals(u,v))
          { o[i] = trueeqn; ++i;
          }
       if(g == '^' && equals(ARG(0,u),ARG(0,v)))
          { if(equals(ARG(0,u),eulere))
               { o[i] = lneqn; ++i;
               }
            else if(equals(ARG(0,u),ten))
               { o[i] = logeqn; ++i;
               }
            else
               { o[i] = logbeqn; ++i;  /* whether solving equations or identities */
               }
            *nops = i;
            return;
          }
       if(g == '^' && ISINTEGER(ARG(0,u)) && ISINTEGER(ARG(0,v)))
          { o[i] = writeintegeraspower; ++i;
          }
       if(g == '^' && (FUNCTOR(ARG(0,u)) == '^' || FUNCTOR(ARG(0,v)) == '^'))
          /* pre-empt introducelninexponent */
          { o[i] = powertopower; ++i; /* example: 2^(6x) = (2^6)^(x^2) */
          }
       if(g == LN || g == LOG || g==LOGB)  /* if we have ln u = ln v, make it u=v */
          { o[i] = powereqn2; ++i;
            *nops = i;
            return;
          }
     }
  if(FUNCTOR(u) == '^' && RATIONALP(v) && RATIONALP(ARG(0,u)))
     /* example, (4/5)^... = 64/125  */
     { o[i] = logbeqn; ++i;
     }
  if(FUNCTOR(u) == '^' && INTEGERP(v))
     { /* example, 5^(...) = 25 */
       if(equals(ARG(0,u), eulere))
          { o[i] = lneqn; ++i;
          }
       else if(equals(ARG(0,u),ten))
          { o[i] = logeqn; ++i;
          }
       else
          { o[i] = logbeqn; ++i;
          }
     }
  /* example,  10^x log 3 = x => x log 3 = log x */
  if(FUNCTOR(u) == ROOT && FUNCTOR(ARG(1,u)) == '^' && econstant(v))
  /* example,  root(5,x^2) = 4. Don't let it become root(5,x)^2 because
     then a substitution u = root(5,x) will be made, which is a long
     way to the solution.
  */
     { o[i] = powereqn; ++i;
     }
  for(j=0;j<2;j++)
     { g = FUNCTOR(ARG(j,t));
       w = ARG(j ? 0 : 1, t);  /* the other side of the equation */
       if(g == '^' &&
          !econstant(ARG(1,ARG(j,t))) && /* nonconstant exponent */
          (econstant(w) || !contains(w,'+'))
          /* don't take the log of a nonconstant sum, that
             leads nowhere and blocks finding successful substitutions
             example: e^(6x) - 6e^(3x) + 5 = 0
          */
         )
          { u = ARG(0,ARG(j,t));
            if(equals(u,ten))
               { o[i] = logeqn; ++i;
                 *nops = i;
                 return;
               }
            if(equals(u,eulere))
               { o[i] = lneqn; ++i;
                 *nops = i;
                 return;
               }
          }
     }
  set_factorflags(t);
  set_pathtail(NULL);   /* some operators tried in set_factorflags can set it */
  if(ZERO(ARG(1,t)) && FRACTION(ARG(0,t)))
     { o[i] = muleqn; ++i;  /* Don't horse around with  a/b = 0 */
       *nops = i;           /* just make it a=0 immediately     */
       return;
     }
  if(ZERO(ARG(1,t)) && FUNCTOR(ARG(0,t)) == '*')
     { o[i] = diveqn; ++i;  /* example, 3(x+2) = 0.  Divide, don't distribute */
     }
  if(ZERO(ARG(1,t)) && NEGATIVE(ARG(0,t)))
     { o[i] = changesigns; ++i;
     }
  if(
     (INTEGERP(ARG(1,t)) || (NEGATIVE(ARG(1,t)) && INTEGERP(ARG(0,ARG(1,t))))) &&
     FUNCTOR(ARG(0,t)) == '*' &&
     INTEGERP(ARG(0,ARG(0,t))) &&
     !cancel(ARG(1,t),ARG(0,ARG(0,t)),&trash,&w) &&
     INTEGERP(w)
    )
     { /* example, 3(x+2) = 6 */
       o[i] = diveqn; ++i;
     }
  if(status(addeqn) > LEARNING ||
     (!additivecancel(ARG(0,t),zero,&w,buffer) &&
      !additivecancel(ARG(1,t),zero,&w,buffer)
     )
    )
     /* when addeqn is LEARNING, we get e.g. 2(1-x) - 2x  = 2x + 9 - 2x, and
        we don't want to cancel the 2x we just subtracted. */
     { o[i] = cancelterm; ++i;  /* cancel additive term on both sides */
     }
  if(status(cancelfactor) >= LEARNING)
     { o[i] = cancelfactor; ++i;  /* cancel common factor on both sides */
     }
  o[i] = switchsides; ++i;  /* get variable on the left if it's
                               only on the right */
  if(  (ZERO(v)  && NEGATIVE(u)) ||
       (NEGATIVE(u) && NEGATIVE(v)) ||
       (ZERO(u)  && NEGATIVE(v))
    )
     { o[i] = changesigns; ++i;
       *nops = i;
       return;
     }
  if(!get_complex() && ZERO(ARG(1,t)) &&
     FUNCTOR(u) == '+' && ARITY(u) == 3
    )
     { o[i] = negativediscriminant; ++i;
       /* reject a quadratic with no real roots
          before you waste time with factorquadratic */
     }

  /* We want to prevent premature substitution into equations that are
   better solved by squaring, for example sqrt(5-2x) - sqrt(x+6) = sqrt(x+3).
   However, we don't want to square now, because we want to wait for what
   is inside the SQRT terms to get simplified.  So squareeqn is not in
   pre_equation, but we still must prevent substitution now. */

  stopsub = mustsq = must_square(t);
  if(stopsub == 0)
     stopsub = stop_sub(u,v);
  if(problemtype != IMPLICIT_DIFF && problemtype != MINMAX)
     { if(stopsub != 2)
        /* stopsub doesn't affect whether try maximalsub except
           in the case of a subterm of the form p-p, indicated by stopsub == 2  */
          { o[i] = maximalsub; ++i;
          }
       if(!stopsub || !different_sqrts(t))
          { o[i] = fractionalsubstitution; ++i;
          }
     }
  if(!stopsub &&
     (
      (problemtype != LINEAR_EQUATIONS  && problemtype != IMPLICIT_DIFF && problemtype != MINMAX)
      ||
      problemtype == LINEAR_EQUATION
     )
    )
     { o[i] = gcdsubstitution; ++i;
       /* don't work on linear equations */
       /* and don't do this when there's a derivative involved
          or you wind up with things like d/d(u^2) which are illegal */
     }
  if(collected(t) > 1 && status(polyvalop) >= KNOWN  &&
     ( 
       (get_currenttopic() != _complex_quadratics  && (get_currenttopic() != _complex_roots || get_pathlength() > 2)) || 
        contains_sqrt(t) || 
        contains_fractional_exponents(t)
     )
       /* we need to simplify inside a square root, but we don't want to simplify
          (x-i)(x+i)-x-i= 0 */
    )
     { o[i] = polyvalop; ++i;
     }
  if(
     ( !block_squareeqn2(t) &&
       !block_squareeqn3(t) &&
       (really_contains_monomially(u,SQRT) && /* this checks u is not econstant */
        !block_squareeqn(v) &&
        !(FRACTION(ARG(0,t)) && special_difofsquares(ARG(1,ARG(0,t))))
        /* This last extremely special condition is needed when the
         left side has the form  sqrt(f(x))/ ((x-sqrt(g(x))(x+sqrt(g(x)))
         and we want it NOT squared so that the denom can get multiplied
         out to x^2-g(x)
        */
       )
     )
     ||
     (really_contains_monomially(v,SQRT) &&
      !block_squareeqn(u) &&
      !(FRACTION(v) && special_difofsquares(ARG(1,v)))
     )
                      /* example:  u =  \sqrt u; just go ahead and square,
                        don't do:  u- \sqrt u = 0; - \sqrt u = -u;  \sqrt u = u; u=u^2 */
                      /* block_squareeqn prevents squaring on  sqrt x = a - sqrt(1/x),
                         which leads to a fourth-degree eqn instead of a quadratic */
    )
     { o[i] = squareeqn; ++i;
       if(!ZERO(u) && !ZERO(v))
          { o[i] = pseudosquare; ++i;
          }
     }
  if(( really_contains_monomially(u,ROOT) && !econstant(u) && !contains_root_of_power(u))
     ||
     ( really_contains_monomially(v,ROOT) && !econstant(v) && !contains_root_of_power(v))
    )
     { o[i] = powereqn; ++i;
     }
  if(!block_crossmultiply(t) && contains(u,'/') && contains(v,'/'))
     { o[i] = crossmultiply; ++i;  /* don't require args to be
                                          fractions because of
                                          (a/b)^n  = (c/d)^m  */
     }
  if(problemtype != IMPLICIT_DIFF &&
     get_currenttopic() != _eqns_by_substitution &&
     !inhibit_transfer(t) &&
     !mustsq   /* also don't transfer if the plan is to square the equation first */
    )
     { o[i] = transfereqn;  ++i;
     }
         /* add or subtract terms to get the variable on the left */
         /* but in implicit differentiation, this should be
            post-associated, so we finish calculating the derivatives
            before transferring all derivatives to the left */

  if(problemtype != LINEAR_EQUATION)
     { o[i] = spliteqn; ++i;     /*  ab=0 iff or(a=0,b=0) */
       o[i] = spliteqn2; ++i;    /*  if ab=ac then a=0 or b=c */
     }
  *nops = i;
}

/*_______________________________________________________________________*/
void solve_equation(term t, int initiali, actualop *o, int *nops)
/* called by post_ops for solving equations */
/* t is an equation; arg is used to return an argument for
the selected operator.  The selected operator (or operators) is
returned in o[initiali] and if needed subsequent values of initiali;
nops is returned as one more than the last index used (i.e., it is the
final dimension of the array o.)
  Some operators will choose their own arg if they are passed an ILLEGAL
arg, specifically:  transfer, cancelterm, diveqn, muleqn.  Hence
solve_equation does not choose an arg for these operators.
*/

{ int i = initiali;
  unsigned short g,h;
  int topic = get_currenttopic();
  term left,right,x,w,c,s;
  int err = derivative_subterm(t,&x);
  int currentline;
  int trigexpandflag = get_trigexpandflag();
  if(err)
     x = get_eigenvariable();
  assert(FUNCTOR(t) == '=');
  left = ARG(0,t);
  right = ARG(1,t);
  currentline = get_currentline();
  if(equals(left,x) &&
     !contains(right,FUNCTOR(x)) &&
     get_checksolutionsflag() &&
     (currentline < 0 || FUNCTOR(history(currentline)) == '=')
        /* don't check solutions one-by-one when there are several
           equations, check them all at once when checkroot is
           post-associated to OR */
    )
    /* equation is already solved */
     { o[i] = checkroot; ++i;
       if(contains(t,PI_ATOM))
          { o[i] = periodicform; ++i;
          }
       *nops = i;
       return;
     }
  g = FUNCTOR(left);
  h = FUNCTOR(right);
  if(ISATOM(ARG(0,t)) &&
     NUMBER(ARG(1,t)) &&
     readpending(&w) == 0
    )
     { o[i] = showcallingcubic; ++i;
     }
  if(topic == _complete_the_square)
     { o[i] = completethesquare; ++i;
     }
  if((g==ABSFUNCTOR && !contains(right,ABSFUNCTOR) && (!econstant(left) || ATOMIC(right)))
     ||
     (h == ABSFUNCTOR && !contains(left,ABSFUNCTOR) && (!econstant(right) || ATOMIC(left)))
    )
     { o[i] = abseqn; ++i;
       o[i] = abseqntoineq1; ++i;
       o[i] = abseqntoineq2; ++i;
       o[i] = squareeqn; ++i;  /* example, abs(2-x) = 4-x  */
       o[i] = pseudosquare; ++i;
       o[i] = abseqnneg; ++i;  /* example, abs(sqrt x + sqrt x) = - x sqrt x
                                  when x >= 0 is an assumption */
     }
  if(must_square(t) ||
     (contains_sqrt2(left) && !contains_root(right,x) && (!FRACTION(left) || contains_sqrt2(ARG(1,left)))) ||
     (contains_sqrt2(right) && !contains_root(left,x) && (!FRACTION(right) || contains_sqrt2(ARG(1,right))))
      /* in sqrt(x-2)/x = 1, do not square, rather first multiply by x. If you
         square first, you will get an absolute value and have to square again,
         but if you multiply first you will be able to use sqrt x = a iff x = a^2
      */
     )
     { o[i] = squareeqn; ++i;
       /* example, sqrt(f(x)) = -1, shows that squareeqn does not have to
          succeed.  Therefore do NOT return here, but throw in more operations,
          e.g. on 2 sqrt x  = -1 you may have to divide by 2 before rejecteqn
          will work. */
       if(!ZERO(left) && !ZERO(right))
          { o[i] = pseudosquare; ++i;
          }
     }
  if(g == '+' && ZERO(right) && FUNCTOR(ARG(0,left)) == '-' &&
     get_orderflag() == DESCENDING  /* don't change signs in  -10 + 10x + x^2 = 0 */
    )
     { o[i] = changesigns; ++i;
       *nops = i;
       return;  /* certain to work */
     }
  if(g == '+' || h == '+')
     { o[i] = muleqn; ++i;  /* eliminate fractions */
     }

  if(g == '/')  /* preops didn't use crossmultiply if it takes variable to
                   the right side when it wasn't already there */
     { if(FUNCTOR(ARG(0,left))==ABSFUNCTOR || FUNCTOR(ARG(1,left))==ABSFUNCTOR)
          { o[i] = abseqn2; ++i;
          }
       if(FUNCTOR(ARG(0,left)) == '^' &&
          FUNCTOR(ARG(1,left)) == '^' &&
          equals(ARG(1,ARG(0,left)),ARG(1,ARG(1,left)))
         )
          /*  a^n /b^n  = (a/b)^n  */
          { o[i] = poweroutoffraction; ++i;
          }
       if(h == '/')
          { o[i] = crossmultiply; ++i;
          }
       else if(ZERO(right) || econstant(ARG(1,left)) || !noxious(ARG(1,left)))
          /* don't multiply if the denom is obviously_nonnegative,
             because then we want to transfer and use common denoms,
             after which multiplying will eliminate the denom. */
          { o[i] = muleqn; ++i;
          }
     }
  if(h == '/' && (ZERO(left) || !noxious(ARG(1,right)))
     && !econstant(right)  // 1.22.25
    )
     { o[i] = muleqn; ++i;
     }
  if(g == '*')
     { if(h != '+')  /* if h == '+' we already threw in muleqn above */
          { o[i] = muleqn; ++i;  /* example:   (1/4)(x-3) = 2, multiply by 4,
                               instead of dividing by 1/4  */
          }
       o[i] = diveqn; ++i;  /* divide by constant factor   */
     }
  if(g == '-' && econstant(right) && !econstant(left))
     { o[i] = changesigns; ++i;
     }
  if( FUNCTOR(left) == COS && FUNCTOR(right) == '*')
     { twoparts(right,x,&c,&s);
       if(FUNCTOR(s) == SIN && equals(ARG(0,s),ARG(0,left)))
          { o[i] = diveqn; ++i;
            *nops = i;
            return;
          }
     }
  if( FUNCTOR(right) == SIN && FUNCTOR(left) == '*')
     { twoparts(left,x,&c,&s);
       if(FUNCTOR(s) == COS && equals(ARG(0,s),ARG(0,right)))
          { o[i] = diveqn; ++i;
            *nops = i;
            return;
          }
     }
  if( FUNCTOR(right) == COS && FUNCTOR(left) == '*')
     { twoparts(left,x,&c,&s);
       if(FUNCTOR(s) == SIN && equals(ARG(0,s),ARG(0,right)))
          { o[i] = diveqn; ++i;
            *nops = i;
            return;
          }
     }


/*  The variable in a polynomial equation is now on the left,  because of
    'transfer' in pre_equation. Constants have been left where they were, however.
     Before moving everything to the left side we need to recognize
     equations like  x^2 + 2x + 1 = c, which should go to
     (x+1)^2 = c now instead of having the c subtracted.  However, in
     general we do NOT want to perform arbitrary factoring.  ONLY in
     case the left side is a square or cube (or nth power) do we want
     to factor now.  In all other cases:
       This is the time to recognize a polynomial equation and bring it to the
    form f(x)=0. More generally, equations which are polynomial in some
    function u(x) should also be recognized.  */

  if(!ZERO(right) && !stop_alltoleft(t))
     { o[i] = alltoleft; ++i;
     }

/*  since factor is turned on by autosimp if the right side is zero, any
  polynomial that can be factored has been factored by now.   Then
  split_eqn will reduce the problem. So if we get past here with a polynomial,
  it can't be factored by MathXpert.
*/
  o[i] = quadraticformula; ++i;
  if(ISATOM(x) && ZERO(right) && !makepoly(ARG(0,t),x,&w) && DEGREE(w) == 3)
      { /* a cubic */
        if(!ZERO(ARG(2,w)))
           { o[i] = eliminatequadraticterm; ++i;
             *nops = i;
             return;
           }
   /*  o[i] = computediscriminant; ++i;
       It is not necessary to compute the discriminant.  It can
       still be done if desired, at the user's initiative. */
        if(status(cardan) >= LEARNING)
           /* But no problemtype sets this yet; so the cubic formulas
              are never used in automode.  If there ever is a problemtype
              for quartic equations, it will be used there. */
           { o[i] = cardan; ++i;
             o[i] = cardan2; ++i;
           }
        else
           { o[i] = viete; ++i;
           }
     }
  if( (g == LOG || g == LN || g == LOGB) &&
      (!contains(right,g) || g==FUNCTOR(right) || econstant(right))
    )
     /* Just take powers without trying to make a substitution first. */
     /* But in log x = (log x)^3, don't take a power first.           */
     /* However, in log x = (log 2)^3, go ahead and take a power.     */
     /* In log x = log f(x)  DO take a power */

     { if(g == LN)
          { o[i] = powereqn3; ++i;
          }
       else if(g == LOG)
          { o[i] = powereqn4; ++i;
          }
       else if(g == LOGB)
          { o[i] = powereqn5; ++i;
          }
     }

/* Find out if the variable occurs more than once.  If not, don't bother
making substitutions but proceed directly to the isolation operators. */

  if(noccurs(x,t) > 1)
     { o[i] = unitelns; ++i;
       o[i] = unitelogs; ++i;
       /* Use lnofpower if afterwards all lns have the same arg */
       /* Example:  ln x = a + ln x^2 => ln x = a + 2 ln x */
       /* lnofpower won't be used when solving equations, instead
          terms like ln x^n  are CREATED in hopes of attracting logs.
          But equations like ln x = a + ln x^n  are counterexamples to
          the attract-collect-isolate equation-solving algorithm */
       o[i] = unitelns2; ++i;  /* Use lnofproduct if afterwards all lns
                                  have the same arg, e.g. ln 3 ln x = ln(3 x) */
       o[i] = unitelogs2; ++i;
       /*  Next, simplify the problem by making a good substitution
           if possible:
           Example:
                 (e^(ix) - e^(-ix) ) / 2i = 4
                 t = e^(ix)
                 t - 1/t = 8i

       */
       set_substitutionflag(VISIBLESUBS);
       if(topic != _implicit_diff)
          { o[i] = makesubstitution; ++i;
            /* e.g. u = x^2; but does not find u = log x;
             see defns.c and autosub.c for explanation */
          }
       if(FUNCTOR(left) == '^' && ISINTEGER(ARG(1,left)) && econstant(right))
          /* makesubstitution explicitly refuses to work on u^2 = constant
             in automode, so it must be handled here. */
          { o[i] = INTDATA(ARG(1,left)) == 2  ? sqrteqn : rooteqn ; ++i;
          }
       *nops = i;
       return;
     }
/* Attraction will work on mathematical expressions, not directly on
equations, so the attraction portion of the algorithm is not found here,
but in postops.c */

/* Next come the isolation operators, now that the variable is on the left.
   Observe that muleqn and diveqn work in auto mode to isolate / and * ,
   and change_signs works to isolate - .
*/
  switch(g)
     { case ROOT:  /* fall-through */
       case SQRT:  o[i] = powereqn; ++i;
                   break;
       case '^' :  /* lneqn, logeqn, and introducelninexponent
                      are used in pre_ops now, so we must have
                      a constant exponent if we get here.  Well,
                      lneqn works only if the right side is obviously_nonnegative,
                      and that might fail even though it is IS nonnegative, so
                      rejecteqn would also fail.  In short you MIGHT get
                      a nonconstant exponent here although I don't have an example.
                      Therefore check for it.
                   */
          if(econstant(ARG(1,left)))
             { if(equals(ARG(1,left),two))
                  { o[i] = sqrteqn; ++i;
                  }
               else
                  { o[i] = rooteqn; ++i;
                    o[i] = powereqn; ++i;  /* x^a = 5 for example, raise to 1/a power */
                  }
             }
          break;
       case SIN:
          o[i] = solvesin30; ++i;
          o[i] = solvesin330; ++i;
          o[i] = solvesin315; ++i;
          o[i] = solvesin60; ++i;
          o[i] = solvesin45; ++i;
          o[i] = solvesin300; ++i;
          o[i] = solvesin0; ++i;
          o[i] = solvesin270; ++i;
          o[i] = solvesin90; ++i;
          o[i] = rejectimpossiblesin; ++i;
          o[i] = solvesin2; ++i;
          o[i] = solvesin; ++i;
          break;
       case COS:
          o[i] = solvecos30; ++i;
          o[i] = solvecos60; ++i;
          o[i] = solvecos150; ++i;
          o[i] = solvecos120; ++i;
          o[i] = solvecos135; ++i;
          o[i] = solvecos45; ++i;
          o[i] = solvecos90; ++i;
          o[i] = solvecos0; ++i;
          o[i] = solvecos180; ++i;
          o[i] = rejectimpossiblecos; ++i;
          o[i] = solvecos; ++i;
          break;
       case TAN:
          o[i] = solvetan30; ++i;
          o[i] = solvetan330; ++i;
          o[i] = solvetan60; ++i;
          o[i] = solvetan120; ++i;
          o[i] = solvetan45; ++i;
          o[i] = solvetan135; ++i;
          o[i] = solvetan0; ++i;
          o[i] = solvetan; ++i;
          break;
       case '*':   /*  e.g. for sec t tan t = c,  or for 2 sqrt n = n-3,
                       we must square the equation */
                   /* powereqn supplies the arg */
                   /* if trig functions are the trigger, it fails unless
                      trigexpandflag != 0 */
          o[i] = powereqn; ++i;
          break;
     }

  if(trigexpandflag & (1 << 12))
     /* No trig functions but sin or cos (but compound args ok) */
     { o[i] = eliminatecossq; ++i;
       o[i] = eliminatesinsq; ++i;
     }
  if(trigexpandflag & (1 << 8))
     /* No trig functions but tan or sec or csc (but compound args ok) */
     /*  e.g.   tan^2 u sec^2 u = 2 => tan^2 u (tan^2 u + 1) = 2 */
    { o[i] = eliminatesecsq; ++i;
      o[i] = eliminatetansq; ++i;
    }
  *nops = i;
  return;
}
/*_______________________________________________________________________*/
static int must_square(term t)
/*  t is an equation.  Catch equations such as cos x =  sin^3 x  that have
to be squared before alltoleft has a chance to work on them.  Return 1
in case you are sure squareeqn should be applied, 0 if it should not
be applied, but alltoleft used instead.   Specifically:  if

(1) there is an odd power (including 1) of a trig function (say cos x ) on one
    side (it will have been isolated there by auto_transfer) and the other
    side is a polynomial in the complementary function (say sin x) which does
    not contain only even powers of sin x  (in that case it could be expressed
    in terms of cos x and we wouldn't need to square).
(2) The left side is a sum of two nonconstant absolute values and the
    right side doesn't contain ABSFUNCTOR and isn't zero.
    Similarly with SQRT in place of ABSFUNCTOR.
    Similarly if the ABSFUNCTOR or SQRT are factors of the summands or factors
    of the num and denom of the summands.
(3) The left side is a sum of two terms which contain SQRT as a factor
    and the right side also has SQRT as a factor
        sqrt(5-2x) - sqrt(x+6) = sqrt(x+3)
    Similarly with ABSFUNCTOR in place of SQRT.
(4) Both sides are SQRTs or powers with exponent 1/2 or ABSFUNCTOR terms or
    positive constants times those things or products of those things
(5) One side is as in (4) and the other side is not obviously_negative.
*/

{ int nn[6];
  term x,u,v,c,s,p,q;
  int count=0,i,err;
  assert(FUNCTOR(t) == '=');
  u = ARG(0,t);
  if(FUNCTOR(u) == '+' && ARITY(u) == 2 &&
     contains_sqrt4(ARG(0,u)) == ABSFUNCTOR && contains_sqrt4(ARG(1,u)) == ABSFUNCTOR &&
     !ZERO(ARG(1,t))
    )
     return 1;  /* case (2) of the documentation */
  if(FUNCTOR(u) == '+' && ARITY(u) == 2 &&
     contains_sqrt4(ARG(0,u)) == SQRT && contains_sqrt4(ARG(1,u)) == SQRT &&
     !ZERO(ARG(1,t))
    )
     return 1;  /* case (2) of the documentation */
  if(FUNCTOR(u) == '+' && ARITY(u) == 2 &&
     contains_halfpower(ARG(0,u)) && contains_halfpower(ARG(1,u)) &&
     !ZERO(ARG(1,t))
    )
    return 1;   /* treat powers of 1/2 like SQRT */
  if(FUNCTOR(u) == '+' && ARITY(u) == 2 &&
     contains_sqrt2(ARG(0,u)) == ABSFUNCTOR && contains_sqrt2(ARG(1,u)) == ABSFUNCTOR &&
     contains_sqrt2(ARG(1,t)) == ABSFUNCTOR &&
     !econstant(ARG(1,t)) && !econstant(ARG(0,u)) && !econstant(ARG(1,u))
    )
     return 1;  /* case (3) of the documentation */
  if(FUNCTOR(u) == '+' && ARITY(u) == 2 &&
     contains_sqrt2(ARG(0,u)) == SQRT && contains_sqrt2(ARG(1,u)) == SQRT &&
     contains_sqrt2(ARG(1,t)) == SQRT &&
     !econstant(ARG(1,t)) && !econstant(ARG(0,u)) && !econstant(ARG(1,u))
    )
     return 1;  /* case (3) of the documentation */
  if(contains_sqrt4(ARG(0,t)) && contains_sqrt4(ARG(1,t)) &&
     (!FRACTION(ARG(0,t)) || ISINTEGER(ARG(1,ARG(0,t)))) &&
     (!FRACTION(ARG(1,t)) || ISINTEGER(ARG(1,ARG(1,t))))
    )
     return 1;  /* case (4) of the documentation */
  if(contains_sqrt4(ARG(0,t)) && !obviously_negative(ARG(1,t)))
     return 1;  /* case (5) of the documentation */
  if(contains_sqrt4(ARG(1,t)) && !obviously_negative(ARG(0,t)))
     return 1;  /* case (5) of the documentation */
  memset(nn,0,sizeof(nn));
  err = assess_trig(t,nn,nn+1,nn+2,nn+3,nn+4,nn+5,0,&x);
     /* counts the odd powers of each trig function */
  if(err)
     return 0;  /* no trig functions, or different args */
  for(i=0;i<6;i++)
     { if(nn[i])
          { ++count;
            nn[i] = 1;  /* we only want to know WHETHER odd powers
                           occur, not HOW MANY  */
          }
     }
  if(count != 2)
     return 0;
  for(i=0;i<3;i++)
     { if( (nn[2*i] + nn[2*i+1]) % 2)
        /* sin and not cos, tan and not sec, cot and not csc */
           return 0;
     }
   /* Now we've definitely got complementary functions */
  u = ARG(1,t);
  v = ARG(0,t);
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(NEGATIVE(v))
     v = ARG(0,v);
  if(econstant(u))
     { /* swap u and v */
       q = u;
       u = v;
       v = q;
     }
  if(odd_trig_power(u) || odd_trig_power(v))
     return 1;
  /* This still doesn't cover  tan x sec x = sqrt 2  */
  if(FUNCTOR(u) == '*')
     { twoparts(u,get_eigenvariable(),&c,&s);
       if(FUNCTOR(s) != '*')
           return must_square(equation(v,s));
       if(ARITY(s) != 2)
           return 0;
       p = ARG(0,s);
       q = ARG(1,s);
       if(econstant(v) &&
          (
           (FUNCTOR(p) == SIN && FUNCTOR(q) == COS) ||
           (FUNCTOR(p) == COS && FUNCTOR(q) == SIN)
          ) &&
          equals(ARG(0,p),ARG(0,q))
         )
          return 0;  /* don't square sin x cos x = constant */
       if(odd_trig_power(p) && odd_trig_power(q))
           return 1;
     }
  if(FUNCTOR(v) == '*')
     { twoparts(v,get_eigenvariable(),&c,&s);
       if(FUNCTOR(s) != '*')
           return must_square(equation(u,s));
       if(ARITY(s) != 2)
           return 0;
       p = ARG(0,s);
       q = ARG(1,s);
       if(odd_trig_power(p) && odd_trig_power(q))
           return 1;
     }
   return 0;
}

/*___________________________________________________________________*/
static unsigned short contains_sqrt4(term a)
/* return ABSFUNCTOR or SQRT or ROOT if a contains an ABSFUNCTOR or SQRT or ROOT
term as a factor or as a factor of num or denom and the other
factors are nonnegative.  Also treat a power of 1/2 as a SQRT.
Return 0 otherwise.
*/
{ unsigned short n,f;
  unsigned short ans,retval;
  int i;
  f = FUNCTOR(a);
  if(f==SQRT || f == ABSFUNCTOR || f == ROOT)
     { if(contains(a, (FUNCTOR(get_eigenvariable()))))
          return f;
       else return 0;
     }
  if(f == '^' && ONEHALF(ARG(1,a)))
     { if(contains(a, FUNCTOR(get_eigenvariable())))
          return SQRT;
       else
          return 0;
     }
  if(f == '-')
     return 0;
  n = ARITY(a);
  if(f == '/')
     { for(i=0;i<n;i++)
          { ans = contains_sqrt4(ARG(i,a));
            if(ans)
               return ans;
          }
     }
  if(f != '*')
     return 0;
  retval = 0;
  for(i=0;i<n;i++)
     { f = FUNCTOR(ARG(i,a));
       if((f == SQRT || f == ABSFUNCTOR || f==ROOT) &&
          contains(ARG(i,a),FUNCTOR(get_eigenvariable()))
         )
          retval = 1;
       else if(POSNUMBER(ARG(i,a)))
          continue;
       else if(!obviously_nonnegative(ARG(i,a)))
          return 0;
     }
  return retval;
}


/*____________________________________________________________*/
static int odd_trig_power(term v)
/* return 1 if v is an odd power (including 1) of a trig function, 0 if not */
{ unsigned short f = FUNCTOR(v);
  term base,power;
  int err;
  unsigned short g;
  if(TRIGFUNCTOR(f))
     return 1;
  if(f != '^')
     return 0;
  base = ARG(0,v);
  power = ARG(1,v);
  g = FUNCTOR(base);
  if(!TRIGFUNCTOR(g))
     return 0;
  if(INTEGERP(power))
     return ODD(power) ? 1 : 0;
  err = infer(odd(power));
  return err ? 0 : 1;
}

/*__________________________________________________________________*/
static int block_crossmultiply(term t)
/* t is an equation; return 1 if there is a good reason NOT
to use cross-multiply on it, 0 if it's ok to try */

{ term left,right;
  assert(FUNCTOR(t) == '=');
  left = ARG(0,t);
  right = ARG(1,t);
  if(econstant(right) &&   /* don't use it on constant denoms */
      (
       FUNCTOR(left) != '/' ||
       (FUNCTOR(left)=='/' && !econstant(ARG(1,left)))
      )
     )
      return 1;
         /* don't use it when one side is a sum of fractions or a product
            one factor of which is a sum of fractions */
  if(sum_of_fractions(left) || sum_of_fractions(right))
     return 1;
  if(SIGNEDFRACTION(left) && !econstant(denom(left)) && noxious(denom(left)))
     return 1; /* better to transfer and use common denoms */
  if(SIGNEDFRACTION(right) && !econstant(denom(right)) && noxious(denom(right)))
     return 1;
  return 0;
}
/*___________________________________________________________*/
static int sqrtrecip(term t)
/* does t contain a subterm of the form sqrt(1/u)? if so return 1. */
{ unsigned short n;
  int i;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t) == SQRT && FRACTION(ARG(0,t)) && ONE(ARG(0,ARG(0,t))))
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(sqrtrecip(ARG(i,t)))
          return 1;
     }
  return 0;
}

/*___________________________________________________________*/
int block_squareeqn2(term t)
/* t is an equation or inequality.  Return 1 if t
contains an expression sqrt(u^2), which will become
an absolute value if it gets a chance, and needs to
do so, e.g. sqrt(x^2)=x if squared will become 'true'
instead of 0 <= x as it should.
*/
{ unsigned short n,f;
  int i;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if(f == SQRT && FUNCTOR(ARG(0,t)) == '^' && iseven(ARG(1,ARG(0,t))))
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(block_squareeqn2(ARG(i,t)))
          return 1;
     }
  return 0;
}

/*___________________________________________________________*/
static int block_squareeqn3(term t)
/* t is an equation or inequality.  Return 1 if for
some reason (not covered in block_squareeqn2 or block_squareeqn)
we don't want to square t.
Example:  sqrt(x) ( sqrt(4x-2) + 6 sqrt x) = 3.  We want to
use distriblaw.
*/
{ unsigned short n,f;
  term u,v;
  int i,k,count=0,count2=0;
  f = FUNCTOR(t);
  assert(INEQUALITY(f));
  for(i=0;i<2;i++)
     { u = ARG(i,t);
       if(econstant(u))
          continue;
       if(NEGATIVE(u))
          u = ARG(0,u);
       if(FUNCTOR(u) != '*')
          continue;
       n = ARITY(u);
       for(k=0;k<n;k++)
           { v = ARG(k,u);
             if(FUNCTOR(v) == SQRT && !econstant(v))
                ++count;
             if(FUNCTOR(v) == '+' && noxious(v))
                ++count2;
           }
       if(count2 == 1 && count >= 1)
          return 1;
     }
  return 0;
}



/*___________________________________________________________*/
static int block_squareeqn(term t)
/* t is one side of an equation whose other side demands to be squared.
Is there a good reason not to square it?  Example:  sqrt x = 2 sqrt 2- sqrt(1/x),
we don't want to square, because after sqrt(1/x) => 1/sqrt x, the substitution
u = sqrt x will yield a quadratic equation instead of a fourth-degree
equation arising from an initial squaring.  I will be very parsimonious
here.
  But one more good reason not to square is if one side is a fraction with
a denom which contains more than one sqrt. In that case we want to transfer and use
common denominators, then multiply by the obnoxious denom.  Example:
sqrt x = 3/(6 sqrt x + sqrt(4x^2-2)).
   Return 1 if we don't want to square t, 0 to NOT block squaring.
*/
{ if(FRACTION(t) && noxious(ARG(1,t)))
     return 1;
  return sqrtrecip(t);
}

/*___________________________________________________________*/
static int contains_root_of_power(term t)
/* return 1 if t is of the form root(n,u^k),
after stripping off constant factors, denominators, and exponents.
Return 0 if not.
*/
{ unsigned short f = FUNCTOR(t);
  unsigned short n;
  int i,flag=0;
  if(ATOMIC(t))
     return 0;
  if(f == ROOT && FUNCTOR(ARG(1,t)) == '^')
     return 1;
  if((f == '/'  || f == '^') && constant(ARG(1,t)))
     return contains_root_of_power(ARG(0,t));
  if(f != '*')
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_root_of_power(ARG(i,t)))
          flag = 1;
       else if(!constant(ARG(i,t)))
          return 0;
     }
  return flag;
}
/*________________________________________________________________*/
int inhibit_transfer(term t)
/* t is an equation or inequality.
Return 1 if there is a good reason NOT to
apply transfereqn.  For example, just after an equation with a
square root has been squared we may have
(-2x sqrt(5-x^2))^2 = (x^2-5)^2  and if we transfer,
then the difference of squares will be factored and we will
go into infinite regress.  We have to simplify first.
*/

{ term u,v,right,left,temp;
  unsigned short f = FUNCTOR(t);
  unsigned short g,h;
  int i;
  assert(INEQUALITY(f));
  for(i=0;i<2;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) == '^')
           { v = ARG(0,u);
             if(NEGATIVE(v))
                v = ARG(0,v);
             if(contains_sqrt(v))  /* also catches ROOT */
                return 1;
           }
     }
  if(get_problemtype() == TESTCONVERGENCE && contains(t,SUM))
     return 1;
  left = ARG(0,t);
  right = ARG(1,t);
  g = FUNCTOR(left);
  h = FUNCTOR(right);
  if(h == '/' && ! econstant(ARG(1,right)) && noxious(ARG(1,right)))
     return 0;   /* example:  sqrt x = 3/(6 sqrt x + sqrt(4x-2).
                    It's better to transfer, use common denoms, and
                    multiply away the obnoxious denominator.  Otherwise
                    we have to square twice and wind up solving a
                    fourth-degree polynomial equation. */
  if(g == '/' && !econstant(ARG(1,left)) && noxious(ARG(1,left)))
     return 0;

  if(ZERO(right) && g == '+' && ARITY(left) == 2)
    { term p,q;
      p = ARG(0,left);
      q = ARG(1,left);
      if(SIGNEDFRACTION(p) && !econstant(denom(p)) &&
         (noxious(denom(p)) || (f != '=' && econstant(q)))
            /* example,  1/3 - 1/(4x) < 0; this goes
               better with common denoms than with transfer.
               But the corresponding equation goes better
               with transfer.
            */
        )
         return 1;
      if(SIGNEDFRACTION(q) && !econstant(denom(q)) &&
         (noxious(denom(q)) || (f != '=' && econstant(p)))
        )
         return 1;
     }
 if(ZERO(left) && h == '+' && ARITY(right) == 2)
    { term p,q;
      p = ARG(0,right);
      q = ARG(1,right);
      if(SIGNEDFRACTION(p) && !econstant(denom(p)) && noxious(denom(p)))
         return 1;
      if(SIGNEDFRACTION(q) && !econstant(denom(q)) && noxious(denom(q)))
         return 1;
     }

  if(econstant(right) && FUNCTOR(left) == '+' && ARITY(left) == 2 &&
     contains_sqrt2(ARG(0,left)) && contains_sqrt2(ARG(1,left))
    )
     /* example:  x/(2 sqrt(x-1))  + sqrt(x-1) = 2 */
     { polyval(product(ARG(0,left),ARG(1,left)),&temp);
       if(!contains(temp,SQRT) && !contains_fractional_exponents(temp))
          return 1;
     }

/* Following equations will get squared in postops if they last that long; but
we want to be sure the args are simplified first, e.g. if sqrt u sqrt u is on the
right we don't want to square.  In the meantime we must prevent transfer from
working in preops. */
  if(
     ((g == ABSFUNCTOR || g == SQRT) && (h == ABSFUNCTOR || h == SQRT || h == '*') && contains_sqrt2(right)) ||
     ((h == ABSFUNCTOR || h == SQRT) && (g == ABSFUNCTOR || g == SQRT || g == '*') && contains_sqrt2(left)) ||
      /* example abs(x) = 3 abs(x+2)  */
      /* but don't square abs(x) = 3 */
     (contains_sqrt2(left) && !contains_sqrt2(right)) ||
     (contains_sqrt2(right) && !contains_sqrt2(left))
    )
     return 1;
  if(
     (f == '<' || f == LE) &&
     g == '/' && FUNCTOR(ARG(0,left)) == SIN &&
     !contains_trig(right) &&
     !contains_trig(ARG(1,left))
    )
     { /* example, sin(1/n) /n < 1/n^2 */
       /* There's a chance of using sin(x) <= x for 0 <= x */
       return 1;
     }
  return 0;
}

/*____________________________________________________________________*/
static int contains_halfpower(term t)
/* return 1 if t is a product or negation of a product and
one of the factors is a power with exponent one-half and the other factors
are nonnegative. */
{ int i,retval;
  unsigned short n;
  if(NEGATIVE(t))
     return 0;
  if(FUNCTOR(t) == '^' && ONEHALF(ARG(1,t)))
     return 1;
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       retval = 0;
       for(i=0;i<n;i++)
          { if(FUNCTOR(ARG(i,t)) == '^' && ONEHALF(ARG(1,ARG(i,t))))
               retval = 1;
            else if(POSNUMBER(ARG(i,t)))
               continue;
            else if(!obviously_nonnegative(ARG(i,t)))
               return 0;  /* give up */
          }
       return retval;
     }
  return 0;
}

/*______________________________________________________________*/
static int contains_root(term t,term x)
/* return 1 if t contains a ROOT, SQRT, ABSFUNCTOR, or power of 1/2 whose
arg contains the variable x, or the functor of non-atomic term x.
In practice x is either a derivative or an atom.
*/
{ unsigned short n,f;
  int i;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if(f == SQRT || f == ABSFUNCTOR || (f == '^' && ONEHALF(ARG(1,t))))
     return contains(ARG(0,t),FUNCTOR(x));
  if(f == ROOT)
     return contains(ARG(1,t),FUNCTOR(x));
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_root(ARG(i,t),x))
          return 1;
     }
  return 0;
}

/*_________________________________________________________________________*/
static int containsPminusP(term t)
/* return 1 if t has a subterm of the form p-p, 0 if not.
*/
{ unsigned short i,n;
  if(ATOMIC(t))
     return 0;
  if(FUNCTOR(t) == '+' && ARITY(t) == 2 &&
     NEGATIVE(ARG(1,t)) &&
     equals(ARG(0,t),ARG(0,ARG(1,t)))
    )
     return 1;
  if(FUNCTOR(t) == '+' && ARITY(t) == 2 &&
     NEGATIVE(ARG(0,t)) &&
     equals(ARG(0,ARG(0,t)),ARG(1,t))
    )
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
    {  if(containsPminusP(ARG(i,t)))
          return 1;
    }
  return 0;
}
/*_________________________________________________________________________*/
static int stop_sub(term u, term v)
/* return nonzero to block the use of maximalsub and fractionalsub in u=v.
Return value 2 indicates the presence of a subterm of the form p-p.
*/
{ term temp,x,p;
  int i;
  term c,s,a,b;
  unsigned short n;
  if(ZERO(u) && !ZERO(v))
     { temp = u;
       u = v;
       v = temp;
     }
  if(SIGNEDFRACTION(v) && !econstant(denom(v)) && noxious(denom(v)))
     return 1;
  if (SIGNEDFRACTION(u) && !econstant(denom(u)) && noxious(denom(u)))
     return 1;
  if(
     ZERO(v) && 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(ZERO(v) && FUNCTOR(u) == '+' && contains(u,'/') && immediate_comdenom(u))
     return 1;
  if(different_sqrts(sum(u,v)))
     return 1;
  if(FUNCTOR(u) == ABSFUNCTOR && equals(ARG(0,u),v))  /* abs v = v */
     return 1;
  if(FUNCTOR(v) == ABSFUNCTOR && equals(ARG(0,v),u))  /* u = abs u */
     return 1;
  if(sqrtcomdenom(u) || sqrtcomdenom(v))
     /* example:  (3/sqrt(x)- 9sqrt(x))^2 = 6x-2, common denoms should
     be used as u = 1/sqrt x leads to twice as long a solution */
     return 1;
  if(ZERO(v))
     { if(NEGATIVE(u))
          u = ARG(0,u);
       if(FUNCTOR(u) == '*')
          { /* look for an arg of u that is linear or quadratic and
               can be inferred nonzero */
            x = get_eigenvariable();
            n = ARITY(u);
            for(i=0;i<n;i++)
               { s = ARG(i,u);
                 if(is_linear_in(s,x))
                    { if(!infer(nonzero(s)))
                         return 1;
                    }
                    /* example: 3(x+1)-x satisfies is_linear_in but makepoly won't
                    recognize it as a polynomial */
                 else if(!makepoly(s,x,&p) && ARITY(p) <= 3 && !infer(nonzero(s)))
                    /* catch quadratics */
                    return 1;
               }
          }
       if(FUNCTOR(u) == '+' && !content_factor(u,&c,&s) &&
          (!infer(nonzero(c)) || !infer(nonzero(s)))
          )
          return 1;  /* example 3 (x+1) sqrt x + x sqrt x */
      if(FUNCTOR(u) == '+' && ARITY(u) == 2)
         { /* catch a linear function  a + bf(x) = 0, so we
              don't substitute u = f(x), find u = -a/b and
              then unwind to f(x) = -a/b instead of going
              directly to f(x) =-a/b */
           x = get_eigenvariable();
           a = ARG(0,u);
           b = ARG(1,u);
           if(NEGATIVE(a))
              a = ARG(0,a);
           if(NEGATIVE(b))
              b = ARG(0,b);
           if(!contains(b,FUNCTOR(x)))
              { temp = a;
                a = b;
                b = temp;
              }
           if(contains(b,FUNCTOR(x)) && !contains(a,FUNCTOR(x)))
              { if(FUNCTOR(b) == '*')
                   { twoparts(b,x,&c,&s);
                     b = s;
                   }
                if(ARITY(b) == 1 && equals(ARG(0,b),x))
                   return 1;
              }
         }
     }
  if(status(polyvalop) <= LEARNING)
     { /* example:  sqrt(x) 2 sqrt(x) - 1 = 0;  when polyvalop is only
       LEARNING, it hasn't been tried yet */
       temp = equation(u,v);
       polyval(temp,&p);
       if(contains(temp,SQRT) && !contains(p,SQRT))
          return 1;
       if(contains_fractional_exponents(temp) && !contains_fractional_exponents(p))
          return 1;
     }
  if(econstant(v) && FUNCTOR(u) == '*')
     { x = get_eigenvariable();
       twoparts(u,x,&c,&s);
       if(FUNCTOR(s) == SQRT)
          return 1;   /* example, 3 sqrt n = 5.  Don't make u = sqrt n,
                         just square directly */
     }
  if(containsPminusP(u) || containsPminusP(v))
     return 2;
  return 0;
}

/*________________________________________________________________*/
static int nsqrts(term t, term x, term *a, term *b)
/* if t contains two different SQRT terms with args linear or quadratic
in x (and not constant) , return the args in *a and *b and  return 2.
If it contains one such SQRT term, put the arg in *a and return 1.
Otherwise return 0. Ignore SQRT terms whose args are not linear or
quadratic in x, or which are constant. */

{ unsigned short f,n;
  int i,r,retval;
  term p,q;
  if(ATOMIC(t))
     return 0;
  retval = 0;
  n = ARITY(t);
  f = FUNCTOR(t);
  for(i=0;i<n;i++)
     { r = nsqrts(ARG(i,t),x,&p,&q);
       if(r == 0)
          continue;
       if(r >= 1 && retval == 1 && !equals(p,*a))
          { *b = p;
            return 2;
          }
       if(r == 2 && retval == 1 && !equals(q,*a))
          { *b = q;
            return 2;
          }
       if(r == 2 && retval == 0)
          { *a = p;
            *b = q;
            return 2;
          }
       if(r == 1 && retval == 0)
          { *a = p;
            retval = 1;
          }
     }
  if(f != SQRT || !contains(t,FUNCTOR(x)))
     return retval;
  if(retval == 0)
     { *a = ARG(0,t);
       if(is_linear_in(ARG(0,t),x))
          return 1;
       if(!makepoly(ARG(0,t),x,&p))
          { if(ARITY(p) <= 3)
               return 1;
          }
     }
  return 0;
}

/*________________________________________________________________*/
int different_sqrts(term t)
/* return 1 if t contains sqrts of two different linear or quadratic
functions of the eigenvariable */
{ term a,b;
  return nsqrts(t,get_eigenvariable(),&a,&b) > 1 ? 1 : 0;
}
/*________________________________________________________________*/
static int really_contains_monomially(term t, unsigned short f)
/* same as contains_monomially if polyvalop is KNOWN or better,
but if it's LEARNING or less, then apply contains_monomially to
the result of polyval on t.
*/
{ term u;
  int ans;
  if(!contains(t,f))
     return 0;   /* without calling the more expensive functions below */
  /* This function is called many times in autosimp so it should be as
     efficient as possible. */
  if(status(polyvalop) >= KNOWN)
     return contains_monomially(t,f);
  polyval(t,&u);
     ans = contains_monomially(u,f);
  destroy_term(u);
  return ans;
}

/*______________________________________________________________________*/
static int fcount(term t, unsigned short f)
/* t is a sum, product, -, or power. If not a sum,
return 1 if t contains a nonconstant term with functor f monomially; if a sum,
return the number of nonconstant summands that contain f monomially.  Note,
the f-part might still be constant, we count it anyway if the summand is
nonconstant.
*/

{ int i, count;
  unsigned short n;
  switch(FUNCTOR(t))
     { case '^':
          return fcount(ARG(0,t),f) + fcount(ARG(1,t),f);
       case '-':
          return fcount(ARG(0,t),f);
       case '+':
          n = ARITY(t);
          count = 0;
          for(i=0;i<n;i++)
             { if(econstant(ARG(i,t)))
                  continue;
               if(contains_monomially(ARG(i,t),f))
                  ++count;
             }
        return count;
     }
  return contains_monomially(t,f) ? 1 : 0;
}

/*_____________________________________________________________________*/
int stop_alltoleft(term t)
/* t is an equation or inequality.  Return 1 if alltoleft should NOT be
used, 0 if it's OK to try it. */
{ unsigned short f = FUNCTOR(t);
  unsigned short g;
  term left,right,x;
  if(!INEQUALITY(f))
     return 1;
  left = ARG(0,t);
  right = ARG(1,t);
  x = get_eigenvariable();
  if(is_linear_in(left,x) && is_linear_in(right,x))
     /* don't use alltoleft on linear equations */
     return 1;
  if (collected(left) < 2 && econstant(right))
        /* only one occurrence of x on the left and right is constant */
      return 1;   /* don't move everything to the left then */
  /* If you change the conditions just above, change the
     conditions in auto_transfer in eqn.c to match */
  g = FUNCTOR(left);
  if( !ATOMIC(left) && g != '*' && g != '+' && g != '^' && g != '-' && g != '/')
      return 1;

  if(!eqpoly(left,x) && !trigpoly2(left,x) &&  fcount(left,ABSFUNCTOR) <= 1 &&
      !(SIGNEDFRACTION(left) && SIGNEDFRACTION(right) &&
      !econstant(NEGATIVE(left) ? ARG(1,ARG(0,left)) : ARG(1,left)) &&
      !econstant(NEGATIVE(right) ? ARG(1,ARG(0,right)) : ARG(1,right)))
    )
     return 1;
  if(get_problemtype() == TESTCONVERGENCE && contains(t,SUM))
     return 1;
  /*  x^2+2x+1 = c  will be factored in pre_ops and then hit with sqrteqn
      and will never come here. */
  /* otherwise proceed--this covers polynomials and trig polynomials,
     whether in standard form or not, but rejects equations with functions
     on the left that may have inverses, including '^', and
     rejects things like  4  \sqrt f(x)  where f is a polynomial */
  /* The part about ABSFUNCTOR is intended to handle examples like
     (abs(x-1) + abs(x+1))^2 = 4.  We need to transfer the 4. However,
     if the left side has no ABSFUNCTOR summand, or only one, we should
     not transfer right to left.
  */
  return 0;
}

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