Sindbad~EG File Manager

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

/* automode solving of a single (linear or nonlinear) inequality for MathXpert */
/*
M. Beeson
Original date 7.7.91
2.19.99 last modified
3.2.00 modified solve_ineq
*/

#define AUTOMODE_DLL
#include <assert.h>
#include <string.h>
#include "globals.h"
#include "checkarg.h" /* for operator typedef */
#include "ops.h"  /* for prototypes of operators */
#include "trig.h"
#include "calc.h"  /* polyvalop */
#include "probtype.h"
#include "eqn.h"
#include "graphstr.h" /* document.h needs it  */
#include "display.h" 
#include "document.h" /* automode.h needs it  */
#include "automode.h"
#include "prover.h"   /* noccurs */
#include "symbols.h"
#include "autosimp.h" /* get_pathlength, get_path */
#include "eqn.h"      /* econstant        */
#include "algaux.h"   /* contains_monomially */
#include "cflags.h"   /* set_factorflag   */
#include "autoeqn.h"  /* inhibit_transfer, stop_alltoleft */
#include "pvalaux.h"  /* obviously_positive */
#include "deval.h"    /* seminumerical      */
#include "domain.h"   /* contains_defined_variables */

static unsigned short contains_sqrt3(term a);
static int one_nonconstant_term(term t);
/*__________________________________________________________________*/
void pre_ineq(term t, actualop *o, int *nops)
/*  Generate a list of operators to be tried in pre_ops when
solving inequalities.  Called by pre_ops.
Put the operators to be used in o[0], o[1],... and return
the number of operators in *nops.  t is an equation.
*/
{ int i=0;
  int problemtype = get_problemtype();
  int pathlength = get_pathlength();
  unsigned short const *path = get_path();
  unsigned short f = FUNCTOR(t);
  term x = get_eigenvariable();
  int strictflag;  /* 1 for < or >,  0 for LE or GE */
  term left,right;
  if(f == '<' || f == LE)
     { left = ARG(0,t);
       right = ARG(1,t);
     }
  else if(f == '>' || f == GE)
     { left = ARG(1,t);
       right = ARG(0,t);
     }
  else
     { *nops = i;  /*  assert(0);  only inequalities get to this function */
       return;
     }
  if(f == '<' || f == '>')
     strictflag = 1;
  else
     strictflag = 0;
  o[i] = arithmetic; ++i;  /* reduce e.g. 0�1 to false */
  if(FUNCTOR(left) == '^' &&
     FUNCTOR(right) == '^' &&
     ISINTEGER(ARG(0,left)) &&
     ISINTEGER(ARG(0,right))
    )
     { o[i] = writeintegeraspower; ++i;
     }
  if(FUNCTOR(left) == '^' && FUNCTOR(right) == '^' &&
     (FUNCTOR(ARG(0,left)) == '^' || FUNCTOR(ARG(0,right)) == '^')
    )
     /* pre-empt introducelninexponent */
     { o[i] = powertopower; ++i; /* example: 2^(6x) = (2^6)^(x^2) */
     }
  if(strictflag && FUNCTOR(left) == ABS)
     { if(ZERO(right))
          { o[i] = f == '<' ? absineqfalse : absineqfalseg; ++i;
          }
       else
          { o[i] = f == '<' ? abslessthanneg : absgreaterthanneg; ++i;
          }
     }
  if(strictflag && FUNCTOR(right) == ABS)
     { o[i] = f == '<' ? absineqtrue3 : absineqtrue3g; ++i;
     }
  if(!strictflag && FUNCTOR(right) == ABS)
     { if(ZERO(left))
          { o[i] = f == LE ? absineqtrue : absineqtrueg; ++i;
          }
       else
          { o[i] = f == LE ? absineqtrue2 : absineqtrue2g; ++i;
          }
     }
  if(!strictflag && FUNCTOR(left) == ABS)
     { o[i] = f == LE ? absleneg : absgeneg; ++i;
       /* abs(u) <= -c is false if c > 0 */
       o[i] = f == LE ? absleneg2 : absgeneg2; ++i;
       /* abs(u) <= -c iff u = 0, after inferring c >= 0 and assuming c = 0 */
     }
  if(problemtype == INDUCTION)
     { o[i] = arithmetic; ++i;
       o[i] = selectinductionvariable; ++i;
       o[i] = useinductionhyp; ++i;
     }
  else if(SOLVETYPE(problemtype) || problemtype == TESTCONVERGENCE)
     { if(!ZERO(right) && !ZERO(left))
          { set_factorflag(0);   /* turn off factoring till right side is zero */
            o[i] = factoroneside; ++i;
            /* example:    x^2 + 2x + 1 < c^2 =>  (x+1)^2 < c^2.  Note that
               after that you have to transfer and factor again, you can't
               just take the square root in general. To see this consider this
               example:  x^4 + 2x^2 + 1 < 1/4.  You get the wrong answer by
               factoring and taking the square root without abs, and if you leave
               abs in you get something intractable.
            */
          }
       else
          { set_factorflag(0x111);   /* turn it back on  */
            if(
                ( ZERO(left) && !is_linear_in(right,x)) ||
                ( ZERO(right) && !is_linear_in(left,x))
              )
               { o[i] = strictflag ? droppositive1 : droppositive2; ++i;
               }
          }
       o[i] = cancelterm; ++i;  /* cancel additive term on both sides */
       if(pathlength >= 2 && path[pathlength-2] != AND)
          { /* don't work on one term of an interval_as_and  */
            o[i] = fractionalsubstitution; ++i;
            o[i] = gcdsubstitution; ++i;
          }
       if(status(polyvalop) >= KNOWN)
          { o[i] = polyvalop; ++i;
          }
       if(contains_sqrt3(t) == SQRT && !ZERO(left) && !ZERO(right))
           /* example:  u = sqrt u; just go ahead and square,
              or at least try (perhaps the side conditions won't be inferred).
              Don't do:  u-sqrt u = 0; -sqrt u  = -u;  sqrt u = u; u=u^2
              the sqrt must be nonconstant and not deeply nested. */
          { o[i] = f == '<' ? powerineq11: powerineq21 ; ++i;
            /* square the inequality sqrt(u) < v */
            if(FUNCTOR(ARG(1,t)) == SQRT && f == '<')
               { o[i] = sqsqrtineq1; ++i;
               }
            if(FUNCTOR(ARG(0,t)) == SQRT && f == '>')
               { o[i] = sqsqrtineq1rev; ++i;
               }
            if(FUNCTOR(ARG(1,t)) == SQRT && f == LE)
               { o[i] = sqsqrtineq2; ++i;
               }
            if(FUNCTOR(ARG(0,t)) == SQRT && f == GE)
               { o[i] = sqsqrtineq2rev; ++i;
               }
            o[i] = f == '<' ? squareineq1 :
                   f == '>' ? squareineq1g :
                   f == LE ? squareineq2 :
                             squareineq2g; ++i;
            o[i] = f == '<' ? squareineq3 :
                   f == '>' ? squareineq3g:
                   f == LE  ? squareineq4:
                              squareineq4g; ++i;
            o[i] = f == '<' ? powerineq12:
                   f == '>' ? powerineq12g:
                   f == LE  ? powerineq22:
                              powerineq22g;  ++i;
          }
       if(contains_sqrt3(t) == ROOT && !ZERO(left) && !ZERO(right) &&
          (contains_monomially(left,ROOT) || contains_monomially(right,ROOT))
         )
          { if(FUNCTOR(ARG(1,t)) == ROOT && f == '<')
               { o[i] = powerrootineq1; ++i;
               }
            if(FUNCTOR(ARG(0,t)) == ROOT && f == '>')
               { o[i] = powerrootineq1rev; ++i;
               }
            if(FUNCTOR(ARG(1,t)) == ROOT && f == LE)
               { o[i] = powerrootineq2; ++i;
               }
            if(FUNCTOR(ARG(0,t)) == ROOT && f == GE)
               { o[i] = powerrootineq2rev; ++i;
               }
            o[i] = f == '<' ? powerineq14odd:
                   f == '>' ? powerineq14oddg:
                   f == LE  ? powerineq24odd:
                              powerineq24oddg; ++i;
            o[i] = f == '<' ? powerineq14even:
                   f == '>' ? powerineq14eveng:
                   f == LE  ? powerineq24even:
                              powerineq24eveng; ++i;
            o[i] = f == '<' ? powerineq13:
                   f == '>' ? powerineq13g:
                   f == LE  ? powerineq23:
                              powerineq23g; ++i;
            o[i] = f == '<' ? powerineq15:
                   f == '>' ? powerineq15g:
                   f == LE  ? powerineq25:
                              powerineq25g; ++i;
          }
       o[i] = crossmultiply; ++i;  /* don't require args to be
                                      fractions because of
                                      (a/b)� = (c/d)^m  */

       /* Next add or subtract terms if required */
       if(!inhibit_transfer(t))
          { o[i] = strictflag ? transferstrictineq : transferineq;  ++i;
          }
       if(f == '=' && problemtype != LINEAR_EQUATION)
          { o[i] = spliteqn; ++i;     /*  ab=0 iff or(a=0,b=0) */
          }

/* example  (x-7)/sqrt(f(x)) < 0, mulineq will not choose sqrt(f(x))
but f(x) sqrt(f(x)), so you will not lose the exclusion of the
codomain of f(x).
*/

       /* Given  u/(f(x))^2 < 0  we want to multiply by (f(x))^2
          immediately, before factoring f(x).  If we used obviously_nonnegative
          instead of obviously_positive in the next lines, it would work on
          x/sqrt(x^2-1) etc. to multiply by the sqrt.  This throws
          the work into the prover behind the scenes, so we really
          should make the polynomial under the square root be
          factored first.
       */
       if(ZERO(right) && FRACTION(left) && obviously_positive(ARG(1,left)))
          { o[i] = mulineq; ++i;
          }
       if(ZERO(left) && FRACTION(right) && obviously_positive(ARG(1,right)))
          { o[i] = mulineq; ++i;
          }
     }
  *nops = i;
}

/*__________________________________________________________________*/
void solve_ineq(term t, int initiali, actualop *o, int *nops)
/* called by post_ops for solving inequalities */
/* t is an equation.  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.)
*/

{ int i = initiali;
  unsigned ineqsymbol = FUNCTOR(t);
  term left,right,u,v,x;
  unsigned f,g,h;
  int sflag;  /* set to 0 for GE or >, to 1 for LE or < */
  int pathlength = get_pathlength();
  unsigned short const *path = get_path();
  if(ineqsymbol == NE)
     { *nops = i;
       return;   /* This isn't supposed to happen, but if through oversight
                    it does, the solution will just stop. No need to crash
                    by hitting the next assertion. */
     }
  assert(ineqsymbol == '<' || ineqsymbol == LE || ineqsymbol == GE || ineqsymbol == '>');
  /* In order to handle all four inequality symbols we set 'sflag' to zero
     for GE or '>' and reverse the left and right sides.  Then when we
     determine which operators to throw in, we check flag again and throw
     in the correct version, for example flag ? absge : absle
  */
  x = get_eigenvariable();
  if(contains(t,FUNCTOR(x)) && solved(t,x))
     goto solved;  /* we may still need to use explicitdomain ('use assumptions') */
  if(ineqsymbol == GE || ineqsymbol == '>')
     { sflag = 0;
       left = ARG(1,t);
       right = ARG(0,t);
       if(ineqsymbol == GE)
          ineqsymbol = LE;
       else
          ineqsymbol = '<';
     }
  else
     { sflag = 1;
       left = ARG(0,t);
       right = ARG(1,t);
     }
  assert(ineqsymbol == '<' || ineqsymbol == LE);
  g = FUNCTOR(left);
  h = FUNCTOR(right);
  if(seminumerical(t))
     { o[i] = numericalineq; ++i;
       *nops = i;
       return;
     }
  if(g==ABS)
     { if(seminumerical(right))
          { o[i] = absineqfalse; ++i;
          }
       if(!ATOMIC(ARG(0,left)))
          { f = FUNCTOR(ARG(0,left));
            switch(f)
               { case SIN:
                    o[i] = abssinineq; ++i;
                    break;
                 case COS:
                    o[i] = abscosineq; ++i;
                    break;
                 case ATAN:
                    o[i] = absarctanineq; ++i;
                    break;
               }
          }
       if(ineqsymbol == '<' && !constant(right) && !block_squareeqn2(t))
          { o[i] = sflag ? squareineq1: squareineq1g; ++i;
            o[i] = sflag ? squareineq3: squareineq3g; ++i;
          }
       else if(ineqsymbol == LE && !constant(right) && !block_squareeqn2(t))
          { o[i] = sflag ? squareineq2: squareineq2g; ++i;
            o[i] = sflag ? squareineq4: squareineq4g; ++i;
          }
     }
  if(h==ABS && ZERO(left))
     { o[i] = absineqtrue; i++;
       o[i] = (ineqsymbol == '<' ? (sflag ? lessthanabs :greaterthanabs) : (sflag ? leabs : geabs)); ++i;
       *nops = i;
       return;
     }
  if(g==ABS &&
      (
        ( is_linear_in(ARG(0,left), x)) ||
        /* e.g.  abs(x+3) < 5  but don't break up  abs sin x < 1/2  */
        (FUNCTOR(ARG(0,left)) == '+' && one_nonconstant_term(ARG(0,left)))
         /* abs(x^2-1) must be broken up */
      )
    )
     { o[i] = (ineqsymbol == '<' ? (sflag ? abslessthan : absgreaterthan) : (sflag ? absle : absge)); ++i;
       *nops = i;
       return;   /* certain to work */
     }
  if(h==ABS && (!ATOMIC(left) || !econstant(right)))
     { o[i] = (ineqsymbol == '<' ? (sflag ? lessthanabs :greaterthanabs) : (sflag ? leabs : geabs));
       ++i;
       *nops = i;
       return;   /* certain to work */
     }
  /* Now for the reciprocal operators */
  if(g == '/' &&
     econstant(right) &&
     econstant(ARG(0,left)) &&
     !obviously_nonnegative(ARG(1,left))
      /* if the denom is positive it's better just to multiply by it.
         Example:   1/abs(x) > 3
      */
    )
     { if(obviously_positive(right))
          /* The following operators will use 'infer' but automode only tries them
             in obvious cases, to avoid long fruitless attempted inferences */
          { o[i] = ineqsymbol == '<' ? (sflag ? recipineq11 : recipineq11g) : (sflag ? recipineq12 : recipineq12g);
            ++i;
          }
       if(obviously_positive(tnegate(right)))
          { o[i] = ineqsymbol == '<' ? (sflag ? recipineq31 : recipineq31g) : (sflag ? recipineq32 : recipineq32g);
            ++i;
          }
     }
  if(h == '/' &&
     econstant(left) &&
     econstant(ARG(0,right)) &&
     !obviously_nonnegative(ARG(1,right))
      /* if the denom is positive it's better just to multiply by it.
         Example:  3 <  1/abs(x)
      */
    )
     { if(obviously_positive(left))
          { o[i] = ineqsymbol == '<' ?
                      (sflag ? recipineq21 : recipineq21g) :
                      (sflag ? recipineq22 : recipineq22g);
            ++i;
          }
       if(obviously_positive(tnegate(left)))
          { o[i] = ineqsymbol == '<' ?
                      (sflag ? recipineq41 : recipineq41g) :
                      (sflag ? recipineq42 : recipineq42g);
            ++i;
          }
     }
  if(g == '/' && h == '/' &&
       (
        ( econstant(ARG(0,left)) && FUNCTOR(ARG(1,left)) == SQRT) ||
        ( econstant(ARG(0,right)) && FUNCTOR(ARG(1,right)) == SQRT)
       )
    )
     { if(ineqsymbol == '<' && !constant(right) && !block_squareeqn2(t))
          { o[i] = sflag ? squareineq1: squareineq1g; ++i;
            o[i] = sflag ? squareineq3: squareineq3g; ++i;
          }
       else if(ineqsymbol == LE && !constant(right) && !block_squareeqn2(t))
          { o[i] = sflag ? squareineq2: squareineq2g; ++i;
            o[i] = sflag ? squareineq4: squareineq4g; ++i;
          }
     }   
  if(g==SIN)
     { o[i] = sinineq; ++i;
     }
  else if(g == COS)
     { o[i] = coslowerbound; ++i;
     }
  else if(g == ATAN)
     { o[i] = arctanineq; ++i;
     }
  else if(h == TAN)
     { o[i] = tanineq; ++i;
     }
  if(g=='+' && ZERO(right) && FUNCTOR(ARG(0,left))=='-' &&
     !(pathlength >= 3 && path[pathlength-3] == AND)
     /* changesigns is called on interval_as_and terms in preops */
    )
     { o[i] = ineqsymbol == '<' ? changesigns1 : changesigns2; ++i;
       *nops = i;
       return;  /* certain to work */
     }
  if(g == '+' && ARITY(left) == 2)
     { u = ARG(0,left);
       v = ARG(1,left);
       if(FUNCTOR(u) == '*' && ARITY(u) == 2 && POSNUMBER(ARG(0,u)))
          u = ARG(1,u);
       if(FUNCTOR(v) == '*' && ARITY(v) == 2 && POSNUMBER(ARG(0,v)))
          v = ARG(1,v);
       if(
          (FUNCTOR(u) == ABS && FUNCTOR(v) == ABS && !contains(right,ABS)) ||
          (FUNCTOR(u) == SQRT && FUNCTOR(v) == SQRT && !contains(right,SQRT)) ||
          (FUNCTOR(u) == '^' && ONEHALF(ARG(1,u)) && FUNCTOR(v) == '^' && ONEHALF(ARG(1,v)))
         )
          { o[i] = ineqsymbol == '<' ?
                    (sflag ? squareineq1: squareineq1g) :
                    (sflag ? squareineq2: squareineq2g); ++i;
            /*  Examples:  abs(x) + abs(x-3) <= 4  */
            /*             sqrt x + sqrt(x-3) <= 4 */
            /*             x^(1/2) + (x-3)^(1/2) <= 4 */
            /*  Squaring the sum will reduce two absolute values to one.
                It is then isolated and squared again to eliminate abs entirely.
            */
          }
     }
  if(ZERO(left) && FUNCTOR(right) == '/' && ineqsymbol == '<' &&
     !econstant(ARG(1,right)) &&
     !( pathlength >= 3 && path[pathlength-3] == AND)
     /* don't use these on one side of an interval_as_and term */
    )
     { o[i] = sflag ? posnum1 : posnum1g; ++i;
       o[i] = sflag ? mulineqsqrt1 : mulineqsqrt1g; ++i;
              /* 0 < u/sqrt v => 0 < uv */
       o[i] = sflag ? mulineqbysquare1: mulineqbysquare1g; ++i;
     }
  if(ZERO(left) && FUNCTOR(right) == '/' && ineqsymbol == LE &&
     !econstant(ARG(1,right)) &&
     !(pathlength >= 3 && path[pathlength-3] == AND)
     /* don't use these on one side of an interval_as_and term */
    )
     { o[i] = sflag ? posnum2: posnum2g; ++i;
       o[i] = sflag ? mulineqsqrt3: mulineqsqrt3g; ++i;
            /* 0 <= u/sqrt v => 0 <= uv */
       o[i] = sflag ? mulineqbysquare3: mulineqbysquare3g; ++i;
     }
  if(ZERO(right) && FUNCTOR(left) == '/' && ineqsymbol == '<' &&
     !( pathlength >= 3 && path[pathlength-3] == AND)
     /* don't use these on one side of an interval_as_and term */
    )
     { o[i] = sflag ? mulineqsqrt2: mulineqsqrt2g; ++i;
          /* u/sqrt v < 0 => uv < 0 */
       o[i] = sflag ? mulineqbysquare2: mulineqbysquare2g; ++i;
     }
  if(ZERO(right) && FUNCTOR(left) == '/' && ineqsymbol == LE &&
     !(pathlength >= 3 && path[pathlength-3] != AND)
     /* don't use these on one side of an interval_as_and term */
    )
     { o[i] = sflag ? mulineqsqrt4: mulineqsqrt4g; ++i;
           /* u/sqrt v <= 0 => uv <= 0 */
       o[i] = sflag ? mulineqbysquare4: mulineqbysquare4g; ++i;
     }
  if( g =='+' || h == '+' ||
      SIGNEDFRACTION(left) ||
      SIGNEDFRACTION(right)
    )
      /* eliminate fractions if denoms have known sign */
     { o[i] = mulineq; ++i;
     }
  if(FRACTION(left) && FUNCTOR(ARG(0,left)) == ABS)
     { o[i] = mulineq; ++i;  /* example: abs(2x+1)/2 < 5x */
       o[i] = mulineqsq; ++i;  /* example: abs(2x+1)/(3x) < 5x */
     }
  if(FRACTION(right) && FUNCTOR(ARG(0,right)) == ABS)
     { o[i] = mulineq; ++i;
       o[i] = mulineqsq; ++i;
     }
  if(g == '*' || h == '*')               /* divide by constant factor */
     { if(ZERO(right) && ineqsymbol == '<')
          { o[i] =  sflag ? normalizelinear1: normalizelinear1g; ++i;
            o[i] =  sflag ? intervalsneg1: intervalsneg1g; ++i;
          }
       else if(ZERO(right) && ineqsymbol == LE)
          { o[i] = sflag ? normalizelinear2: normalizelinear2g; ++i;
            o[i] = sflag ? intervalsneg2: intervalsneg2g; ++i;
          }
       else if(ZERO(left) && ineqsymbol == '<')
          { o[i] = sflag ? normalizelinear1: normalizelinear1g; ++i;
            o[i] = sflag ? intervalspos1: intervalspos1g; ++i;
          }
       else if(ZERO(left) && ineqsymbol == LE)
          { o[i] = sflag ? normalizelinear2: normalizelinear2g; ++i;
            o[i] = sflag ? intervalspos2: intervalspos2g; ++i;
          }
       if(contains_sqrt3(t))
          { o[i] = mulineq; ++i;   /* example, (1/4)(x-3) < 2, multiply by 4 */
          }
       o[i] = divineq; ++i;
     }
  if(g == SQRT)
     { o[i] = ineqsymbol == '<' ?
                 (sflag ? powerineq11: powerineq11g):
                 (sflag ? powerineq21: powerineq21g); ++i;
       *nops = i;
       return;
     }
  if(g == ROOT)
     { o[i] = ineqsymbol == '<' ?
                 (sflag ? powerineq14odd: powerineq14oddg):
                 (sflag ? powerineq24odd: powerineq24oddg); ++i;
       o[i] = ineqsymbol == '<' ?
                 (sflag ? powerineq14even: powerineq14eveng):
                 (sflag ? powerineq24even: powerineq24eveng); ++i;
       *nops = i;
       return;
     }
  if(g == '-' && econstant(right) && !econstant(left) &&
       /* work on -x < 3, but not on -3 < x */
     !(pathlength >= 3 && path[pathlength-3] == AND)
       /* changesigns is called on interval_as_and terms in preops */
    )
     { o[i] = ineqsymbol == '<' ?
                 (sflag ? changesigns1: changesigns1g):
                 (sflag ? changesigns2: changesigns2g); ++i;
     }
  if(h == '-' && !econstant(right) && econstant(left) &&  /* work on 3 < -x, but not on  x < - 3 */
     !(pathlength >= 3 && path[pathlength-3] == AND)
     /* changesigns is called on interval_as_and terms in preops */
    )
     { o[i] = ineqsymbol == '<' ?
                 (sflag ? changesigns1: changesignsandsense3):
                 (sflag ? changesigns2: changesignsandsense4); ++i;
                 /* -x > 3 becomes x < - 3 rather than -3 > x;
                 note that in this case '-x' is 'right', not 'left',
                 because args of > were switched at the top of the function. */
     }
  if(g == '-' && contains_sqrt(left) && !contains_sqrt(right) &&
     !(!econstant(right) && econstant(left)) && /* stop loop with above conditions */
     !(pathlength >= 3 && path[pathlength-3] == AND)
     /* changesigns is called on interval_as_and terms in preops */
    )
     { o[i] = ineqsymbol == '<' ?
                 (sflag ? changesigns1: changesigns1g):
                 (sflag ? changesigns2: changesigns2g); ++i;
     }
  if(h == '-' && contains_sqrt(right) && !contains_sqrt(left) &&
     !(!econstant(left) && econstant(right))  && /* stop loop with above conditions */
     !(pathlength >= 3 && path[pathlength-3] == AND)
     /* changesigns is called on interval_as_and terms in preops */
    )
     { o[i] = ineqsymbol == '<' ?
                 (sflag ? changesigns1: changesigns1g):
                 (sflag ? changesigns2: changesigns2g); ++i;
     }

/*    This is the time to recognize a
    polynomial inequality and bring it to the form f(x) < 0.
    However, on an inequality like x < sqrt(x^2+1), we don't want
    to put everything on the left.
*/
  if(!econstant(left) && !contains_sqrt3(left) &&
     /* don't use alltoleft if the result will have two summands containing a sqrt
        or root, because this will loop with autotransfer */
     !(contains_sqrt(right) && FUNCTOR(right) == '+' && contains_sqrt(left)) &&
     /* If there's a sum on the right, you can go ahead and transfer it,
        and later isolate one root. */
     !stop_alltoleft(t)
    )
     { o[i] = alltoleft; ++i;
     }
  /* the condition prevents looping:  0 < f(x); -f(x) < 0; 0 < f(x)... */
  /* changesigns will work if we have 0 < -f(x); otherwise just leave
     everything on the right. */

/*  since factor is on while solving equations,  any polynomial that can
    be factored will be factored now.   Then split_ineq will reduce the problem.
    So if we get past here with a polynomial, it can't be factored by Mathpert.
    quadraticformula has been applied in autosum, don't repeat it here
*/

  o[i] = completethesquare; ++i;
  if(g == LN && econstant(right))
     { o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
       *nops = i;
       return;
     }
  if(h == LN && econstant(left))
     { o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
       *nops = i;
       return;
     }
  if(g == LOG && econstant(right))
     { o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
       *nops = i;
       return;
     }
  if(h == LN && econstant(left))
     { o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
       *nops = i;
       return;
     }
  if(g == '^')
     { if(isinteger(ARG(1,left)) && iseven(ARG(1,left)) && econstant(right))
          { o[i] = ineqsymbol == '<' ?
                      (sflag ? sqrtineq14: sqrtineq14g):
                      (sflag ? sqrtineq24: sqrtineq24g); ++i;
            if(equals(ARG(1,left),two))
               { o[i] = ineqsymbol == '<' ?
                           (sflag ? squarefalse1 : squarefalse1g):
                           (sflag ? squarefalse2 : squarefalse2g); ++i;
               }
            else
               { o[i] = ineqsymbol == '<' ?
                           (sflag ? evenpowerineq3: evenpowerineq3g):
                           (sflag ? evenpowerineq4: evenpowerineq4g); ++i;
               }
            *nops = i;
            return;
          }
       if(equals(ARG(0,left),eulere) && econstant(right))
          { o[i] = ineqsymbol == '<' ? lnineq1 : lnineq2;
            ++i;
            *nops = i;
            return;
          }
       if(equals(ARG(0,left),ten) && econstant(right))
          { o[i] = ineqsymbol == '<' ? logineq1 : logineq2;
            ++i;
            *nops = i;
            return;
          }
       if(FUNCTOR(ARG(1,left))=='/')  /* fractional exponent */
          { o[i] = ineqsymbol == '<' ?
                     (sflag ? powerineq16: powerineq16g):
                     (sflag ? powerineq26: powerineq26g); ++i;
            *nops = i;
            return;
          }
       if(econstant(ARG(1,left)) && econstant(right))
           { o[i] = ineqsymbol == '<' ?
                       (sflag ? oddrootineq: oddrootineqg):
                       (sflag ? oddrootineq2: oddrootineq2g); ++i;
             o[i] = ineqsymbol == '<' ?
                       (sflag ? rootineq13: rootineq13g):
                       (sflag ? rootineq23: rootineq23g); ++i;
             o[i] = ineqsymbol == '<' ?
                       (sflag ? evenpowerineq3: evenpowerineq3g):
                       (sflag ? evenpowerineq4: evenpowerineq4g); ++i;
             *nops = i;
             return;
           }
     }
  if(h == '^')
     {
       if(isinteger(ARG(1,right)) && iseven(ARG(1,right)) && econstant(left))
           { o[i] = ineqsymbol == '<' ?
                       (sflag ? sqrtineq15: sqrtineq15g):
                       (sflag ? sqrtineq25: sqrtineq25g); ++i;
             if(equals(ARG(1,right),two))
                { o[i] = ineqsymbol == '<' ?
                            (sflag ? squaretrue1: squaretrue1g):
                            (sflag ? squaretrue2: squaretrue2g); ++i;
                }
             else
                { o[i] = ineqsymbol == '<' ?
                            (sflag ? evenpowerineq1: evenpowerineq1g):
                            (sflag ? evenpowerineq2: evenpowerineq2g); ++i;
                }
             *nops = i;
             return;
           }
       if(equals(ARG(0,right),eulere) && econstant(left))
           { o[i] = (ineqsymbol == '<' ? lnineq1 : lnineq2);
             ++i;
             *nops = i;
             return;
           }
       if(equals(ARG(0,right),ten) && econstant(left))
           { o[i] = (ineqsymbol == '<' ? logineq1 : logineq2);
             ++i;
             *nops = i;
             return;
           }
       if(FUNCTOR(ARG(1,right))=='/')  /* fractional exponent */
           { o[i] = ineqsymbol == '<' ?
                       (sflag ? powerineq16: powerineq16g):
                       (sflag ? powerineq26: powerineq26g); ++i;
             *nops = i;
             return;
           }
       if(econstant(ARG(1,right)) && econstant(left))
           { o[i] = ineqsymbol == '<' ?
                       (sflag ? oddrootineq: oddrootineqg):
                       (sflag ? oddrootineq2: oddrootineq2g); ++i;
             o[i] = ineqsymbol == '<' ?
                       (sflag ? rootineq15: rootineq15g):
                       (sflag ? rootineq25: rootineq25g); ++i;
             o[i] = ineqsymbol == '<' ?
                       (sflag ? evenpowerineq1: evenpowerineq1g):
                       (sflag ? evenpowerineq2: evenpowerineq2g); ++i;
             *nops = i;
             return;
           }
     }
  if(g == LN)
     { o[i] = ineqsymbol == '<' ?
                ( sflag ? lnleftineq1: lnleftineq1g):
                ( sflag ? lnleftineq2: lnleftineq2g); ++i;
     }
  if(g == LOG)
     { o[i] = ineqsymbol == '<' ?
                ( sflag ? logleftineq1: logleftineq1g):
                ( sflag ? logleftineq2: logleftineq2g); ++i;
     }
  if(g == LOGB)
     { o[i] = ineqsymbol == '<' ?
                ( sflag ? powerineq17: powerineq17g):
                ( sflag ? powerineq27: powerineq27g); ++i;
     }
  if(h == LN)
     { o[i] = ineqsymbol == '<' ?
                ( sflag ? lnrightineq1: lnrightineq1g):
                ( sflag ? lnrightineq2: lnrightineq2g); ++i;
     }
  if(g == LOG)
     { o[i] = ineqsymbol == '<' ?
                ( sflag ? logrightineq1: logrightineq1g):
                ( sflag ? logrightineq2: logrightineq2g); ++i;
     }
  if(g == LOGB)
     { o[i] = ineqsymbol == '<' ?
                ( sflag ? powerineq17: powerineq17g):
                ( sflag ? powerineq27: powerineq27g); ++i;
     }
  if(get_problemtype() == IMPLICIT_DIFF || noccurs(get_eigenvariable(),t) > 1)
     { /* if possible, simplify the problem by making a good substitution */
       o[i] = makesubstitution; ++i;
     }

/* Next come the isolation operators, now that the variable is on one side.
   Observe that muleqn and diveqn work in auto mode to isolate / and * ,
   and change_signs works to isolate - .
*/
  if(econstant(left))
     {
       if(h==SQRT && ineqsymbol == '<')
          { o[i] = sflag ? powerineq12: powerineq12g; ++i;
            *nops = i;
            return;
          }
       if(h==SQRT && ineqsymbol == LE)
          { o[i] = sflag ? powerineq22: powerineq22g; ++i;
            *nops = i;
            return;
          }
       if(h==ROOT && ineqsymbol == '<')
          { o[i] = sflag ? powerineq15: powerineq15g; ++i;
            *nops = i;
            return;
          }
       if(h==ROOT && ineqsymbol == LE)
          { o[i] = sflag ? powerineq25: powerineq25g; ++i;
            *nops = i;
            return;
          }
     }
  solved:
  if(pathlength <= 3 &&
     /* pathlength <= 3 means apply it only to top-level inequalities, not
        to inequalities that may have been generated by previous calls to
        explicitdomain.
     */
     !(pathlength >=3 && path[pathlength-3] == AND) &&
        /* explicitdomain will be applied directly to an interval_as_and. */
     solved(t,get_eigenvariable()) &&
     !contains_defined_variables(t)  /* wait till definitions have been unwound */
    )
     { o[i] = explicitdomain; ++i;
     }
  *nops = i;
  return;
}


/*___________________________________________________________________*/
static unsigned short contains_sqrt3(term a)
/* return ABS or SQRT or ROOT if a contains an ABS or SQRT or ROOT
term as a factor or as a factor of num or denom.  Similar to
contains_sqrt2 in eqn.c but does not allow minus signs.
*/
{ unsigned short n,f;
  unsigned short ans;
  int i;
  f = FUNCTOR(a);
  if(INEQUALITY(f))
     { i = contains_sqrt3(ARG(0,a));
       if(i)
          return (unsigned short) i;
       return contains_sqrt3(ARG(1,a));
     }
  if(f==SQRT || f == ABS || f == ROOT)
     { if(contains(a, FUNCTOR(get_eigenvariable())))
          return f;
       else
          return 0;
     }
  n = ARITY(a);
  if(f == '/')
     { for(i=0;i<n;i++)
          { ans = contains_sqrt3(ARG(i,a));
            if(ans)
               return ans;
          }
     }
  if(f != '*')
     return 0;
  for(i=0;i<n;i++)
     { f = FUNCTOR(ARG(i,a));
       if((f == SQRT || f == ABS || f==ROOT) &&
          contains(ARG(i,a),FUNCTOR(get_eigenvariable()))
         )
          return f;
     }
  return 0;
}
/*_____________________________________________________________________*/
static int one_nonconstant_term(term t)
/* t is a sum.  Return 1 if it has exactly one nonconstant summand */
{ unsigned short n = ARITY(t);
  int i;
  int count=0;
  if(FUNCTOR(t) != '+')
     return 0;
  for(i=0;i<n;i++)
     { if(!econstant(ARG(i,t)))
          ++count;
     }
  return count == 1 ? 1 : 0;
}

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