Sindbad~EG File Manager

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

/*  reduce_ineq,  simplify inequalities for Mathpert's theorem prover */
/*  M. Beeson
1.29.91  Original date
6.4.99  modified
1.4.00  added code for 0 < ln u iff 1 < u, search for LN to find it
2.28.00 added a couple of lines to simple_bounds
2.28.00 corrected 'return 1' to 'return 0'  at simple_bounds line 2161 and 2165
2.28.00 added more lines to simple_bounds so it can get sin(x) <= x when x >= 0.
12.16.10 added code around line 182 so ln(x) != 0 will reduce to x != 1
1.14.11 added code to one_sign to recognize x + sqrt(x^2 + 1) as having one sign
1.15.11 similarly for x-sqrt(x^2+1)
9.15.11 added calls to copy around lines 1590-1610
5.2.13  added code to reduce_ineq at line 1054 to catch |2k \pm 1| < 1 and return false.
1.6.15  moved declaration out of switch statement to quiet a warning
11.15.20 moved declaration to legal C position
8.8.24  replaced math.h with sincos.h
1.8.25  added code at line 273
*/

#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include "globals.h"
#include "prover.h"
#include "probtype.h"
#include "algaux.h"
#include "cancel.h"
#include "order.h"
#include "eqn.h"
#include "simpprod.h"
#include "fraction.h"
#include "factor.h"
#include "solvelin.h"
#include "deval.h"
#include "evaltrig.h"
#include "trig.h"   /* cancelfactorial2 */
#include "infsup.h"
#include "pvalaux.h"  /* mvpolymult2     */
#include "reset.h"    /* save_and_reset  */
#include "ops.h"      /* explicitdomain  */
#include "ssolve.h"   /* ssolve          */
#include "nextline.h" /* strip_multiplicities */
#include "polynoms.h" /* makepoly        */
#include "binders.h"  /* get_binders     */
#include "trigdom.h"  /* hasroot         */
#include "invineq.h"  /* invert_ineq     */
#include "fastdom.h"  /* too_complicated */
#include "redineq.h"

static int cancel_identical(unsigned short, term, term, term *);
static int reduce_fractional_ineq(unsigned short, term, term, term *);
static int solve_it(term, term, unsigned short, term *);
static int one_sign(term);
static int easy_sign(term);
static int reduce_trigsum(term t, term *ans);
static int contains_binders(term t);
/*________________________________________________________________*/
int reduce_ineq(term t, term *ans)
/* one-step reduction of inequalities and '='.
   return 0 for a successful reduction, 1 for failure.
   In case it returns 1, *ans is returned as t, but
   not in fresh space.
      Returns 3 for low memory; if less than 24K heap is available
   it fails immediately.
   (This function includes all reductions to
    be applied before conjoin, disjoin.)
*/
{ term a,b,u,v,temp,temp2,x,cancelled,trash,w;
  unsigned short n,m,f,g,h,k;
  int i,err;
  int complex = get_complex();
  double z;
  long kk;
  void  *savenode;
  int savenextdefn, saveeigen, nvariables;
  unsigned long nbytes;
  short savenextassumption;
  termlist *binders;
  f = FUNCTOR(t);
  if(contains(t,ILLEGAL))
    { *ans = t;
      return 1;  // something has gone wrong before now, let's not make things worse.
    }
  assert(ARITY(t)==2);
  assert (f == '<' || f == LE || f == NE || f == '=');
  if(PRIME(t))
      { *ans = t;
        return 1;   /* already processed */
      }
  nbytes = mycoreleft();
  if(nbytes < 24576)
     { *ans = t;
       return 3;
     }
  savenode = heapmax();
  int nvars = get_nvariables();
  savenextdefn = get_nextdefn();
  savenextassumption = get_nextassumption();
  nvariables = get_nvariables();
  saveeigen = get_eigenindex();
  if(contains(t,SIN) || contains(t,COS) ||
     contains(t,ATAN) || contains(t,ACOT)
    )
     { err = simple_bounds(t,ans);  /* can it be deduced from -1 <= sin t  etc.  */
       if(!err)
          return 0;
     }
  a = ARG(0,t);
  b = ARG(1,t);
  g = FUNCTOR(a);
  h = FUNCTOR(b);
  if(equals(b,infinity) && f == LE)
     { *ans = trueterm;
       return 0;
     }
  if(equals(a,minusinfinity) && f == LE)
     { *ans = trueterm;
       return 0;
     }
  if(equals(a,complexi) && seminumerical(b) && f != NE)
     { *ans = falseterm;  /* refute i < 0 etc. */
       return 0;
     }
  if(equals(b,complexi) && seminumerical(a) && f != NE)
     { *ans = falseterm; /* refute 0 < i etc. */
       return 0;
     }
  if(ZERO(a) && f == LE && obviously_nonnegative(b))
     { *ans = trueterm;
       return 0;
     }
  if(ZERO(a) && (f == '<' || f == NE) && obviously_positive(b))
     { *ans = trueterm;
       return 0;
     }
  if(f == NE &&
      (
         (ZERO(a) && obviously_nonzero(b)) ||
         (ZERO(b) && obviously_nonzero(a))
      )
     )
       { *ans = trueterm;
         return 0;   /* example, 1/c != 0  */
         /* Even if c is undefined, e.g.  1/0 != 0 still reduces to true */
       }
  if(f == '=' &&
      (
         (ZERO(a) && obviously_nonzero(b)) ||
         (ZERO(b) && obviously_nonzero(a))
      )
    )
       { *ans = falseterm;
         return 0;
       }
  if(equals(b,infinity) && (f != '<' || !equals(a,infinity)))
     { *ans = domain(a);
       return 0;  /* example:  0 <= infinity */
     }
  if(equals(a,infinity))  /* infinity < c  is false, even if c = infinity */
                          /* even infinity <= infinity is false    */
     { *ans = falseterm;
       return 0;
     }
  if(equals(b,minusinfinity))
     { *ans = falseterm;
       return 0;
     }
  if(ATOMIC(a) && ATOMIC(b))
     { if(get_binders())
           { err =  nonstandard(t,ans);
             if(err)
                *ans = t;
             return err;  /* this line allows inspecting ans in the debugger */
           }
       else
          { *ans = t;
            return 1;  /* can't be processed further */
          }
     }
  if(equals(a,minusinfinity) && !equals(b,minusinfinity))
     { *ans = trueterm;
       return 0;
     }
  err = cancel_identical(f,a,b,ans);  /* identical terms on both sides? */
  if(!err)
     return 0;
  if(ZERO(a) && (h == LN || h == LOG || h == LOGB))
     /* 0 < ln u iff 1 < u */
     { *ans =  make_term(f,2);
       ARGREP(*ans,0,one);
       ARGREP(*ans,1,ARG(h == LOGB ? 1 : 0,b));
       return 0;
     }
  if(ZERO(b) && (g == LN || g == LOG || g == LOGB))
     /* ln u  < 0 iff  u  < 1 */
     { *ans =  make_term(f,2);
       ARGREP(*ans,1,one);
       ARGREP(*ans,0,ARG(g == LOGB ? 1 : 0,a));
       return 0;
     }
  if(ZERO(a) && h == SQRT)
     { switch(f)
          { case NE:
            case '<':
               *ans = lessthan(zero,ARG(0,b));
               return 0;
            case LE:
               *ans = le(zero,ARG(0,b));
               return 0;
            case '=':
               *ans = equation(ARG(0,b),zero);
               return 0;
          }
     }
  if(ZERO(b) && g == SQRT)
     { switch(f)
          { case NE:
               *ans = lessthan(zero,ARG(0,a));
               return 0;
            case '<':
               if(!get_complex())
                  *ans = falseterm;
               else
                  *ans = lessthan(zero, im(ARG(0,a)));
               return 0;
            case LE:
               if(!get_complex())
                  *ans = equation(ARG(0,a),zero);
               else
                  *ans = le(zero,im(ARG(0,a)));
               return 0;
            case '=':
               *ans = equation(ARG(0,a),zero);
               return 0;
          }
     }
  if(ZERO(a) && h == ROOT && iseven(ARG(0,b)))
     { switch(f)
          { case NE:
            case '<':
               *ans = lessthan(zero,ARG(1,b));
               return 0;
            case LE:
               *ans = le(zero,ARG(1,b));
               return 0;
            case '=':
               *ans = equation(ARG(1,b),zero);
               return 0;
          }
     }
  if(ZERO(b) && g == ROOT && iseven(ARG(0,a)))
     { switch(f)
          { case NE:
               *ans = lessthan(zero,ARG(1,a));
               return 0;
            case '<':
               if(!get_complex())
                  *ans = falseterm;
               else
                  *ans = lessthan(zero, im(ARG(1,a)));
               return 0;
            case LE:
               if(!get_complex())
                  *ans = equation(ARG(1,a),zero);
               else
                  *ans = le(zero,im(ARG(1,a)));
               return 0;
            case '=':
               *ans = equation(ARG(1,a),zero);
               return 0;
          }
     }
   if(ONE(b) && g == ABSFUNCTOR &&
     FUNCTOR(ARG(0,a)) == '^' &&
     iseven(ARG(1,ARG(0,a)))
    )
     { *ans = make_term(f,2);
       ARGREP(*ans,1,one);
       ARGREP(*ans,0,abs1(ARG(0,ARG(0,a))));
       return 0;
     }
  if(ZERO(a) && h == ROOT && isodd(ARG(0,b)))
     { *ans = make_term(f,2);
       ARGREP(*ans,0,zero);
       ARGREP(*ans,1,ARG(1,b));
       return 0;
     }
  if(ZERO(b) && g == ROOT && iseven(ARG(0,a)))
     { *ans = make_term(f,2);
       ARGREP(*ans,0,ARG(1,a));
       ARGREP(*ans,2,zero);
       return 0;
     }
  if(ZERO(a) && h =='^')  /*  0 < u^v  (or \le or != ) */
     { u = ARG(0,b);
       v = ARG(1,b);
       if(f == '=')
          { *ans = lpt(equation(zero,u));
            if(contains(*ans, ILLEGAL))
               { *ans = t;
                 return 1;
               }
            return 0;
          }
       if(f == NE)
          { *ans = lpt(ne(u,zero));
             if(contains(*ans, ILLEGAL))
               { *ans = t;
                 return 1;
               }
            return 0;
          }
       if(f == LE)  /* and !complex */
          { if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
               { *ans = get_polyvaldomainflag() ? domain(v) : trueterm;
                 return 0;
               }
            if(NEGATIVE(v))
               return reduce_ineq(lessthan(zero,make_power(u,ARG(0,v))),ans);
            if(INTEGERP(v))  /* far the most common case, speed it up */
               { *ans = ISODD(v) ? le(zero,u) : trueterm;
                 return 0;
               }
            if(RATIONALP(v))  /* speed this up too */
               { if(ISODD(ARG(0,v)))  /* x^(1/2) or x^(1/3) */
                    { if(ISODD(ARG(1,v)))
                         *ans = trueterm;  /* x^(1/3) */
                      else
                         *ans = get_polyvaldomainflag() ? le(zero,v) : trueterm;
                         /* x^(1/2) for example */
                    }
                 else
                    *ans = trueterm;
                 return 0;
               }
            *ans = make_term(OR,4);
            ARGREP(*ans,0,lessthan(zero,u));
            ARGREP(*ans,1, and(equation(u,zero),ne(v,zero)));
            ARGREP(*ans,2,even(v));
            ARGREP(*ans,3,and(odd(denom1(v)),even(numerator1(v))));
            return 0;
          }
       if(f == '<')  /* and !complex */
          { if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
               { *ans = trueterm;
                 return 0;
               }
            if(NEGATIVE(v))
                v = ARG(0,v);
            if(INTEGERP(v))  /* far the most common case, speed it up */
               { *ans = ISODD(v) ?  lessthan(zero,u) : ne(zero,u);
                 return 0;
               }
            if(RATIONALP(v))
               { if(ISODD(ARG(0,v)))
                    { if(ISODD(ARG(1,v)))
                         *ans = trueterm; /* x^(1/3) */
                      else  /* x^(1/2) */
                         *ans = lessthan(zero,u) ;
                    }
                 else
                    *ans = get_polyvaldomainflag() ? ne(u,zero) : trueterm;
                    /* x^(2/5) for example */
                 return 0;
               }
            if(immediate(lessthan(zero,u)) == 1)
               { *ans = trueterm;
                 return 0;  /* this helps when u is the index variable in a series */
               }
            if(OBJECT(v) && TYPE(v) == DOUBLE)
               { double z = DOUBLEDATA(v);
                 long kk;
                 if(nearint(z,&kk))
                     { if(kk & 1)
                           { *ans = lessthan(zero,u);
                             return 0;
                           }
                       *ans = ne(u,zero);
                       return 0;
                     }
                  *ans = lessthan(zero,u);
                  return 0;
                }
            *ans = and(ne(zero,u),
                       or3(lessthan(zero,u),
                           even(v),
                           and(odd(denom1(v)),even(numerator1(v)))
                          )
                      );
            return 0;
          }
     }
  if(h == MAXFUNCTOR && (f == LE || f == '<'))
     { /* x < max(u,v)  =>  x < u or x < v */
       u = make_term(f,2);
       v = make_term(f,2);
       ARGREP(u,0,a);
       copy(a,ARGPTR(v));  /* not ARGREP(v,0,a), so as not to create a DAG */
       ARGREP(u,1,ARG(0,b));
       ARGREP(v,1,ARG(1,b));
       *ans = or(u,v);
     }
  if(h == MINFUNCTOR && (f == LE || f == '<'))
     { /* x < min(u,v)  =>  x < u and x < v */
       u = make_term(f,2);
       v = make_term(f,2);
       ARGREP(u,0,a);
       copy(a,ARGPTR(v));  /* not ARGREP(v,0,a), so as not to create a DAG */
       ARGREP(u,1,ARG(0,b));
       ARGREP(v,1,ARG(1,b));
       *ans = and(u,v);
       return 0;
     }
  if(ZERO(b) && g == '^')  /*   u^v < 0 (or LE, !=, = ) */
     { u = ARG(0,a);
       v = ARG(1,a);
       if(f == '=')
          { *ans = lpt(equation(zero,u));
            if(equals(*ans,falseterm) || obviously_nonzero(v))
               return 0;
            if(!cancel(u,v,&cancelled,&trash) && obviously_nonzero(trash))
               { *ans = falseterm;  /* x^x is never zero, also x^(2x) etc. */
                 return 0;
               }
            if(get_polyvaldomainflag())
               { *ans = and(*ans, ne(v,zero));
               }
            return 0;
          }
       if(f == NE)
          { if(NEGATIVE(v))
               v = ARG(0,v);
            if(complex || INTEGERP(v) || (RATIONALP(v) && ISODD(ARG(1,v))))
               { *ans = ne(u,zero);
                 return 0;
               }
            if(RATIONALP(v) && ISEVEN(ARG(1,v)))
               { *ans = lessthan(zero,u);
                 return 0;
               }
            if(obviously_positive(u)) /* this takes care of e^x != 0 */
               { *ans = trueterm;
                 return 0;
               }

            if(!constant(v))
               /* neglect the possibility of a negative base and integer exponent or
                  rational exponent with odd denominator where u^v could be defined and
                  nonzero; this makes complicated expressions which makes it impossible
                  to analyze integrands.  We simply assume that for variable exponents,
                  the definition u^v = e^v ln u  is used. */
               { *ans = lessthan(zero,u);
                 return 0;
               }
            w = lpt(le(zero,u));
            if(equals(w,trueterm))
               {  /* example, analyzing integral(1/x^s,x,0,1), we get
                     here and want to return 0 < s for *ans instead of
                     a complicated expression as below. */
                 *ans = lessthan(zero,u);
                 return 0;
               }
            *ans = or3(
                       and(type(v,INTEGER),ne(u,zero)),
                       lessthan(zero,u),
                       and(ne(u,zero),odd(denom1(v)))
                      );
            return 0;
          }
       if(f=='<')
          { if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
               { *ans = falseterm;
                 return 0;
               }
            if(NEGATIVE(v))
               v = ARG(0,v);
            if(INTEGERP(v) && ISEVEN(v))
               { *ans = falseterm;
                 return 0;
               }
            if(INTEGERP(v))  /* && ISODD(v) */
               { *ans = lessthan(u,zero);
                 return 0;
               }
            if(RATIONALP(v) && ISODD(ARG(1,v)))
               { *ans = lessthan(u,zero);
                 return 0;
               }
            if(RATIONALP(v) && ISEVEN(ARG(1,v)))
               { *ans = falseterm;
                 return 0;
               }
            *ans = and(
                       lessthan(u,zero),
                       or(
                          odd(v),
                          and(odd(denom1(v)),odd(numerator1(v)))
                         )
                      );
            return 0;
          }
       if(f==LE)
          { if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
               { *ans = falseterm;
                 return 0;
               }
            *ans = or(
                      and(
                          le(u,zero),
                          or(
                             odd(v),
                             and(odd(denom1(v)),odd(numerator1(v)))
                            )
                         ),
                      and(equation(u,zero), lessthan(zero,v))
                     );
            return 0;
          }
     }
  if(ZERO(a) && f == LE  && h == '+')
     { /* a sum of absolute values is non-negative */
       for(i=0;i<ARITY(b); i++)
          { if(FUNCTOR(ARG(i,b)) != ABSFUNCTOR)
               break;
          }
       if(i==ARITY(b))
          { *ans = trueterm;
            return 0;
          }
     }
  if(ZERO(a) && h == '+' && ARITY(b) == 2 && isdifofsquares(b))
     /* 0 < x^2-y^2  =>  y^2 < x^2 */
     { temp = make_term(f,2);
       if(NEGATIVE(ARG(1,b)))
          { ARGREP(temp,0, ARG(0,ARG(1,b)));
            ARGREP(temp,1, ARG(0,b));
            reduce_ineq(temp,ans);
            return 0;
          }
       else
          { ARGREP(temp,0, ARG(0,ARG(0,b)));
            ARGREP(temp,1,ARG(1,b));
            reduce_ineq(temp,ans);
            return 0;
          }
     }
  if(ZERO(b) && g == '+' && ARITY(a) == 2 && isdifofsquares(a))
     /* x^2-y^2 < 0 => x^2 < y^2 */
     { temp = make_term(f,2);
       if(NEGATIVE(ARG(1,a)))
          { ARGREP(temp,1, ARG(0,ARG(1,a)));
            ARGREP(temp,0, ARG(0,a));
            reduce_ineq(temp,ans);
            return 0;
          }
       else
          { ARGREP(temp,1, ARG(0,ARG(0,a)));
            ARGREP(temp,0,ARG(1,a));
            reduce_ineq(temp,ans);
            return 0;
          }
     }
  if(ZERO(b) && FUNCTOR(a) == ABSFUNCTOR && (f == '=' || f == NE))
     { *ans = f == '=' ? equation(ARG(0,a),zero) : ne(ARG(0,a),zero);
       return 0;  /* abs(x) == 0 iff x == 0 */
     }
  if(ZERO(a) && FUNCTOR(b) == ABSFUNCTOR && (f == '=' || f == NE))
     { *ans = f == '=' ? equation(zero,ARG(0,b)) : ne(zero,ARG(0,b));
       return 0;
     }
  if(ZERO(b) && ATOMIC(a))    /* a < 0 */
       /* check whether a:NATNUM is an assumption */
     { int nextassumption = get_nextassumption();
       u = type(a,NATNUM);
       for(i=0;i<nextassumption;i++)
          { if (equals(get_assumption(i),u))
               break;
          }
       if(i < nextassumption)  /* a:natnum was found */
          { if(f == '<')
               { *ans =  falseterm;
                 return 0;
               }
            if(f == LE)
               { *ans = equation(a,zero);
                 return 0;
               }
            if(f == NE)
               { *ans = lessthan(zero,a);
                 return 0;
               }
          }
     }
  if(ZERO(a) && ATOMIC(b) && f == LE)
       /* check whether b:NATNUM is an assumption */
     { int nextassumption = get_nextassumption();
       u = type(b,NATNUM);
       for(i=0;i<nextassumption;i++)
          { if (equals(get_assumption(i),u))
               break;
          }
       if(i<nextassumption) /* b:natnum was found */
          { *ans = trueterm;
            return 0;
          }
     }
  if(f == '=' && ZERO(a) && h == '*')
    /*  0 = xy => xy = 0 */
     { u = equation(b,a);
       reduce_ineq(u,ans);
       return 0;
     }
    /*  uv = 0  reduces to or(u=0,v=0), deleting obviously nonzero factors*/
    /*  uv != 0 reduces to and(u!=0,v!=0), deleting obviously nonzero factors */
  if((f == '=' || f==NE) && ZERO(b) && g == '+' && contains(a,'^'))
     { /* use polyval to factor it , e.g. x^4 + 3x^2 */
       int savefactorflag = get_polyvalfactorflag();
       int savecomdenomflag = get_polyvalcomdenomflag();
       int savegcdflag = get_polyvalgcdflag();
       int savefactorflag2 = get_polyvalfactorflag2();
       int savelogflag = get_polyvallogflag();
       int savefunctionflag = get_polyvalfunctionflag();
       set_polyvalfactorflag(1);
       set_polyvalfunctionflag(1);
       set_polyvallogflag(1);
       set_polyvalfactorflag2(0x100);
       set_polyvalcomdenomflag(1);
       UNSET_ALREADY(a);
         /* in case a was processed when factoring was off, it may still
            have the ALREADY bit set.  That may have happened long ago
            so it's not enough to do this only when saveit is 0.  */
       err = polyval(a,&u);
       set_polyvalfactorflag(savefactorflag);
       set_polyvalcomdenomflag(savecomdenomflag);
       set_polyvalgcdflag(savegcdflag);
       set_polyvallogflag(savelogflag);
       set_polyvalfunctionflag(savefunctionflag);
       set_polyvalfactorflag2(savefactorflag2);
       /* I observed an example in which polyval takes a sum of 6 terms
          and re-orders the terms, and then on the recursive call reorders
          them to the original order, causing a loop.  Hopefully ordering
          of terms is unique, but in order to be sure we don't make a
          recursive call if only the order of terms has changed.
       */
       if(err || eqtest(a,u))
          destroy_term(u);  /* and keep going */
       else
          { v = make_term(f,2);
            ARGREP(v,0,u);
            ARGREP(v,1,zero);
            reduce_ineq(v,ans);
            return equals(t,*ans) ? 1 : 0;
          }
     }
  if((f == NE || f == '=') && ZERO(b) && g == '+' && !complex)
     {  /* catch a case like x^4 + x^2 + 1 which has no real roots */
       if(one_sign(a))
          { *ans = (f==NE ? trueterm : falseterm);
             return 0;
          }
     }
  if((f==LE || f == '<') && ZERO(a) && h == '+' && !complex)
     { int sign = one_sign(b);
       if(sign)
          { *ans = (sign > 0 ? trueterm : falseterm);
            return 0;
          }
     }
  if((f==LE || f == '<') && ZERO(b) && g == '+' && !complex)
     { int sign = one_sign(a);
       if(sign)
          { *ans = (sign > 0 ? falseterm : trueterm);
            return 0;
          }
     }
  if((f == '=' || f==NE) && ZERO(b) && g == '*')
     { /* delete obviously nonzero factors and return an OR or AND */
       k = 0;
       n = ARITY(a);
       temp = (f== '=' ? make_term(OR,n) : make_term(AND,n));
       for(i=0;i<n;i++)
          { if(!obviously_nonzero(ARG(i,a)))
               { v = (f == '=' ? equation(ARG(i,a),zero) : ne(ARG(i,a),zero));
                 ARGREP(temp,k,v);
                 k++;
               }
          }
       if(k==0)
          { *ans = (f == NE ? trueterm : falseterm);
            RELEASE(temp);
            return 0;
          }
       if(k==1)
          { *ans = ARG(0,temp);
            RELEASE(temp);
            return 0;
          }
       *ans = temp;
       SETFUNCTOR(*ans,FUNCTOR(temp),k);
       return 0;   /* even if k==n, since we changed uv=0 to or(u=0,v=0) */
     }
  /* given  0 < uv,  remove obviously positive or negative factors and
     return a new inequality.  Reduce_ineq does not take 0 < uv apart into
     a Boolean combination of inequalities involving u and v separately. */
  if((f == '<' || f== LE) &&
     ((ZERO(a) && h == '*') || (ZERO(b) && g == '*'))
    )
     { int sign;
       unsigned short kk=0;
       term tt,uval;
       if(ZERO(b))
          { b=a;
            a= zero;
            sign = -1;   /* will cause reversal of inequality in the end*/
          }
       else
          sign = 1;   /* net sign of cancelled factors */
       /* delete obviously one-signed factors and return an OR or AND */
       k = 0;
       n = ARITY(b);
       temp = make_term('*',n);
       /* accumulate the not-obviously-one-signed factors in temp */
       if(f == '<')
          tt = make_term(AND,n);
       for(i=0;i<n;i++)
          { double zz;
            term w = ARG(i,b);
            if(seminumerical(w))
               { err = deval(w,&zz);
                 if(!err)
                    { if(zz < 0.0)
                         sign = (sign > 0 ? -1 : 1);
                      continue;
                    }
               }
            u =  f == '<' ? lessthan(zero,w) : le(zero,w);
            v =  f == '<' ? lessthan(w,zero) : le(w,zero);
            uval = lpt(u);
            if(immediate(uval)==1)
               { RELEASE(u);
                 RELEASE(v);
                 continue;
               }
            if(immediate(lpt(v))==1)
               { sign = (sign > 0 ? -1 : 1);
                 RELEASE(u);
                 RELEASE(v);
                 continue;
               }
            if(f == '<')  /* example, 0 < x^2y^2 */
               { u = le(zero,w);
                 if(immediate(lpt(u)) == 1)
                    { ARGREP(tt,kk,uval);  /* in the example, uval is x != 0 */
                      ++kk;
                    }
                 else
                    { ARGREP(temp,k,w);
                      ++k;
                    }
               }
            else  /* f == LE and can't immediately determine sign of ARG(i,b)) */
               { ARGREP(temp,k,w);
                 ++k;
               }
            RELEASE(u);
            RELEASE(v);
          }
       SETFUNCTOR(tt,AND,kk);  /* whether or not f == '<'; harmless anyway */
       if(k==0)  /* could determine the sign of every arg */
          { if(sign < 0)
               { *ans = falseterm;
                  RELEASE(temp);
                  if(f == '<')
                     RELEASE(tt);
                  return 0;
                }
            assert(sign > 0);
            if(kk==0)
               { *ans = trueterm;
                 RELEASE(temp);
                 if(f == '<')
                     RELEASE(tt);
                 return 0;
               }
            *ans = tt;
            return 0;
          }
       if(k==1)
          { *ans = make_term(f,2);
            if(sign > 0)
               { ARGREP(*ans,0,zero);
                 ARGREP(*ans,1,ARG(0,temp));
               }
            else
               { ARGREP(*ans,0,ARG(0,temp));
                 ARGREP(*ans,1,zero);
               }
            if(kk)
               { SETFUNCTOR(tt,AND,(unsigned short)(kk+1));
                 ARGREP(tt,kk,*ans);
                 *ans = tt;
               }
            RELEASE(temp);
            return 0;
          }
       *ans = make_term(f,2);
       SETFUNCTOR(temp,FUNCTOR(temp),k);
       if(sign > 0)
          { ARGREP(*ans,0,zero);
            ARGREP(*ans,1,temp);
          }
       else
          { ARGREP(*ans,0,temp);
            ARGREP(*ans,1,zero);
          }
       if(kk)
          { SETFUNCTOR(tt,AND,(unsigned short)(kk+1));
            ARGREP(tt,kk,*ans);
            *ans = tt;
          }
       /* Now check whether anything was actually changed: */
       if(! equals(*ans,t))
          return 0;
     }
 /*  look for a common factor to cancel out from both sides */

  if(!ZERO(a) && !ZERO(b) && !ONE(a) && !ONE(b) &&
     !ISATOM(a) && !ISATOM(b) &&  /* don't cancel 1/3 from x = -1/3 */
     !equals(a,minusone) && !equals(b,minusone)
    )
     { term cancelled;
       if(contains_sqrt(a) || contains_sqrt(b))
          err = supercancel(a,b,&cancelled,&temp);
       else
          err = cancel(a,b,&cancelled,&temp);
       if(!err)   /* something cancelled */
          { if(FRACTION(temp))
               SETFUNCTOR(temp,f,2);   /* change it to an inequality */
            else
               { temp2 = temp;
                 temp = make_term(f,2);
                 ARGREP(temp,0,temp2);
                 ARGREP(temp,1,one);
               }
            if( seminumerical(cancelled) &&
                !deval(cancelled,&z) &&
                fabs(z) > VERYSMALL
              )
               { if(f == '=' || f == NE)
                    *ans = temp;
                 else  if(z > 0.0)
                    *ans = temp;
                 else  /*if z < 0.0 */
                    { *ans = make_term(f,2);
                      ARGREP(*ans,0,ARG(1,temp));
                      ARGREP(*ans,1,ARG(0,temp));
                    }
                 return 0;
               }
            /* Now it was not a numerical term that cancelled */
            if(f == '=')
               { *ans = or(temp,equation(cancelled,zero));
                 return 0;
               }
            if(f == NE)
               { *ans = and(ne(cancelled,zero),temp);
                 return 0;
               }
            temp2 = make_term(f,2);
            ARGREP(temp2,0,ARG(1,temp));
            ARGREP(temp2,1,ARG(0,temp));
            if(f == '<')
               { *ans = or(
                           and(lessthan(zero,cancelled),temp),
                           and(lessthan(cancelled,zero),temp2)
                          );
               }
            else
               { *ans = or(
                           and(le(zero,cancelled),temp),
                           and(le(cancelled,zero),temp2)
                          );
               }
            return 0;
          }
     }
  if(g == '-' && h == '-')  /* -u < -v iff v < u */
     { u = ARG(0,a);
       v = ARG(0,b);
       *ans = make_term(f,2);
       if(f == '=' || f == NE)
          { ARGREP(*ans,0,u);
            ARGREP(*ans,1,v);
          }
       else
          { ARGREP(*ans,0,v);
            ARGREP(*ans,1,u);
          }
       return 0;
     }
  if(g == ABSFUNCTOR && obviously_nonnegative(ARG(0,a)))
     { *ans = make_term(f,2);
       ARGREP(*ans,0,ARG(0,a));
       if(FUNCTOR(b) == ABSFUNCTOR && obviously_nonnegative(ARG(0,b)))
          ARGREP(*ans,1,ARG(0,b));
       else
          ARGREP(*ans,1,b);
       return 0;
     }
  if(h == ABSFUNCTOR && obviously_nonnegative(ARG(0,b)))
     { *ans = make_term(f,2);
       ARGREP(*ans,0,a);
       ARGREP(*ans,1,ARG(0,b));
       return 0;
     }
  if(g == ABSFUNCTOR && FRACTION(ARG(0,a)) && obviously_positive(ARG(1,ARG(0,a))))
     /* |c/2| < b  iff |c| < 2b  for example */
     { *ans = make_term(f,2);
       ARGREP(*ans,0,abs1(ARG(0,ARG(0,a))));
       ARGREP(*ans,1,product(ARG(1,ARG(0,a)),b));
       return 0;
     }
  if(g == '/' || h == '/')
     { err = reduce_fractional_ineq(f,a,b,ans);
       if(!err)
          return 0;
     }
  if(g == '^' && h == '^' && equals(ARG(1,a),two) && equals(ARG(1,b),two))
    /* u^2 f v^2 => ...  */
     { term u2,u3,u4,v2;
       u = ARG(0,a);
       v = ARG(0,b);
       
       switch(f)
           { case '=': /* u = v or u = -v */
                *ans = or(equation(u,v),equation(u,tnegate(v)));
                return 0;
             case NE:  /* u != v and u != -v */
                *ans = and(ne(u,v),ne(u,tnegate(v)));
                return 0;
             case LE:  /* 0 <= u <= v or v <= u <= 0 */
                copy(u,&u2);
                copy(u,&u3);
                copy(u,&u4);
                copy(v,&v2);
                *ans = or(and(le(zero,u),le(u2,v)),and(le(v2,u3),le(u4,zero)));
                return 0;
             case '<':  /* 0 <= u <= v or v <= u <= 0 */
                copy(u,&u2);
                copy(u,&u3);
                copy(u,&u4);
                copy(v,&v2);
                *ans = or(and(le(zero,u),le(u2,v)),and(le(v2,u3),le(u4,zero)));
                return 0;
           }
     }
  if(g == VECTOR && (f == '=' || f == NE))
       /*  (p,q,0) is identified with (p,q) */
     { assert(h == VECTOR);  /* else an ill-formed term has crept in! */
       n = ARITY(a);
       m = ARITY(b);
       k = (unsigned short)(n < m ? m : n);  /* max of m and n */
       *ans = make_term((unsigned short)(f=='=' ? AND : OR), n);
       for(i=0;i<k;i++)
          { u = make_term(f,2);
            ARGREP(u,0,(i<n ? ARG(i,a): zero));
            ARGREP(u,1,(i<m ? ARG(i,b): zero));
            ARGREP(*ans,i,u);
          }
       return 0;
     }
  if(ZERO(b) && g == '+' && ARITY(a) == 2 &&
     FUNCTOR(ARG(1,a))== '-' && FUNCTOR(ARG(0,ARG(1,a))) != '+'
    )
     { *ans = make_term(f,2);  /* change a-b < 0 to a < b etc. */
       ARGREP(*ans,0,ARG(0,a));
       ARGREP(*ans,1,ARG(0,ARG(1,a)));
       return 0;
     }
  if(ZERO(a) && h == '+' && ARITY(b) == 2 &&
     FUNCTOR(ARG(1,b))== '-' && FUNCTOR(ARG(0,ARG(1,b))) != '+'
    )
     { *ans = make_term(f,2);  /* change 0 < x-y to y < x etc. */
       ARGREP(*ans,1,ARG(0,b));
       ARGREP(*ans,0,ARG(0,ARG(1,b)));
       return 0;
     }
  if(ZERO(b) && g == '+' && ARITY(a) == 2 &&
     FUNCTOR(ARG(0,a))== '-' && FUNCTOR(ARG(0,ARG(0,a))) != '+'
    )
     { *ans = make_term(f,2);  /* change -y+x < 0 to x < y etc. */
       ARGREP(*ans,0,ARG(1,a));
       ARGREP(*ans,1,ARG(0,ARG(0,a)));
       return 0;
     }
  if(ZERO(a) && h == '+' && ARITY(b) == 2 &&
     FUNCTOR(ARG(0,b))== '-' && FUNCTOR(ARG(0,ARG(0,b))) != '+'
    )
     { *ans = make_term(f,2);  /* change 0 < -y+x to y < x etc. */
       ARGREP(*ans,1,ARG(1,b));
       ARGREP(*ans,0,ARG(0,ARG(0,b)));
       return 0;
     }

   /* change a/b+c != 0 to a != -bc */
   /* example,  1 + 1/sin x  != 0   */
  if( (f == NE || f == '=')  &&
      ZERO(b) && g == '+' &&
      ARITY(a) == 2 && (FRACTION(ARG(0,a)) || FRACTION(ARG(1,a))) &&
      !(FRACTION(ARG(0,a)) && FRACTION(ARG(1,a)))
    )
     { term p,q,r,s;
       *ans = make_term(f,2);
       if(FRACTION(ARG(0,a)))
          { p = ARG(0,ARG(0,a));
            r = ARG(1,ARG(0,a));
            q = ARG(1,a);
          }
       else
          { p = ARG(0,ARG(1,a));
            r = ARG(1,ARG(1,a));
            q = ARG(0,a);
          }
       s = product(r,q);
       if(constant(s))
          { ARGREP(*ans,0,p);
            ARGREP(*ans,1,tnegate(s));
          }
       else
          { ARGREP(*ans,0,s);
            ARGREP(*ans,1,tnegate(p));
          }
       return 0;
     }
  if(ZERO(a) && h == '+' && ARITY(b)==2 && FUNCTOR(ARG(1,b)) == '-')
     { *ans = make_term(f,2);
       ARGREP(*ans,0,ARG(0,ARG(1,b)));
       ARGREP(*ans,1,ARG(0,b));
       return 0;
     }
  if(ZERO(a) && h == '+' && ARITY(b) == 3)
     /* catch quadratics with negative discriminant and positive
        quadratic term, these are positive */
     { term *atomlist,aa,bb,cc,xx,yy;
       int natoms = atomsin(b,&atomlist);
       double aval,bval,cval;
       free2(atomlist);
       if(natoms == 1 && isquadratic(b,&aa,&bb,&cc,&xx,&yy))
          { deval(aa,&aval);
            deval(bb,&bval);
            deval(cc,&cval);
            if(fabs(aval) <= 1.0e150 &&    /* guard against overflow */
               fabs(bval) <= 1.0e150 &&
               fabs(cval) <= 1.0e150 &&
               (bval*bval - 4.0 *aval *cval) < 0  /* negative discriminant */
              )
                { *ans = aval > 0.0 ? trueterm : falseterm;
                  return 0;
                }
          }
     }
  binders = get_binders();
  if(binders && (f=='<' || f == LE  || f == NE))
     { err = nonstandard(t,ans);
       if(!err)  /* nonstandard tries to eliminate the nonstandard
                    variable, but there might not be one, or
                    it might not succeed. */
          return 0;
       if(get_lpt_binderflag() && (f == '<' || f == NE))
          { /* for definite integrals, if one side of the inequality is
            zero and the other a polynomial, use coste-roy rather than
            trying to factor. Coste-roy, in sturm.c, uses generalized
            Sturm sequences.  hasroot is in trigdom.c */
            term left,right,x,q;
            POLYnomial p;
            double dleft, dright;
            int nvars,nroots;
            term *atomlist;
            nvars = variablesin(t,&atomlist);
            if(ONE(b) && FUNCTOR(a) == ABSFUNCTOR && f == '<')
                { /* example, |2k-1| < 1,  impossible with k an integer  */
                  term z = ARG(0,a);
                  term *atomlist3;
                  int m = variablesin(z,&atomlist3);
                  int i;
                  for(i=0;i<m;i++)
                      { term u = atomlist3[i];
                        if(TYPE(u) == INTEGER) 
                             { // see if z is of the form pu \pm q  with p, q integers
                               if(
                                  equals(z,u) ||
                                  ( FUNCTOR(z) == '*' && INTEGERP(ARG(0,z)) && equals(ARG(1,z),u))
                                 )
                                   { *ans = falseterm;
                                     free2(atomlist3); 
                                     free2(atomlist);
                                     return 0;
                                   }
                               if(FUNCTOR(z) == '+' && ARITY(z) == 2)
                                   { term p = ARG(0,z);
                                     term q = ARG(1,z);
                                     if(INTEGERP(q) || (NEGATIVE(q) && INTEGERP(ARG(0,q))))
                                          { if(equals(p,u))
                                                { *ans = falseterm;
                                                  free2(atomlist3); 
                                                  free2(atomlist);
                                                  return 0;
                                                }
                                            if(FUNCTOR(p) == '*' && INTEGERP(ARG(0,p)) && equals(ARG(1,p),u))
                                                { *ans = falseterm;
                                                  free2(atomlist3);
                                                  free2(atomlist);
                                                  return 0;
                                                }
                                          }
                                    }
                              }
                        }
                    }
                                   
            if(ZERO(a))
               q = b;
            else
               q = a;
            if(nvars == 1 && !binders_interval(&left,&x,&right) &&
               equals(x,atomlist[0]) &&
               !deval(left,&dleft) && !deval(right,&dright) && dleft < dright &&
               dleft != BADVAL && dright != BADVAL &&
               !makepoly(q,x,&p) && DEGREE(p) >= 2
              )
               { /* it's a definite integral or sum */
                 free2(atomlist);
                 RELEASE(p);
                 nroots = hasroot(q,x,dleft,dright,1,1);
                 if(nroots > 0)
                    *ans = falseterm;
                 else if(nroots == 0) /* it has no root */
                                     /* nroots < 0 signals an error */
                    { if(f == NE)
                         *ans = trueterm;
                      else /* determine the sign of q on (left,right) */
                         { double saveit = VALUE(x);
                           double z;
                           SETVALUE(x,0.5 *(dright+dleft));
                           deval(q,&z);
                           SETVALUE(x,saveit);
                           assert(z != 0);
                           if(z > 0.0)
                              *ans = ZERO(a) ? trueterm : falseterm;
                           else
                              *ans = ZERO(a) ? falseterm : trueterm;
                         }
                    }
                 return 0;
               }
            else
               free2(atomlist);
          }

     }
  switch(f)
     { case '<'  :
          if(ZERO(a) && ARITY(b)==1 && FUNCTOR(b) != IMAGPART && FUNCTOR(b) != REALPART)
             { if(FUNCTOR(b)=='-')
                  *ans = lessthan(ARG(0,b),zero);
               else
                  *ans = posval(FUNCTOR(b),ARG(0,b));
               return 0;
             }
          if(ZERO(b) && ARITY(a)==1 && FUNCTOR(a) != IMAGPART && FUNCTOR(a) != REALPART)
             { if(FUNCTOR(a)=='-')
                  *ans = lessthan(zero,ARG(0,a));
               else
                  *ans = negval(FUNCTOR(a),ARG(0,a));
               return 0;
             }
          break;

       case  LE:
          if(ZERO(a) && ARITY(b)==1  && FUNCTOR(b) != IMAGPART && FUNCTOR(b) != REALPART)
             { if(FUNCTOR(b)== '-')
                  *ans = le(ARG(0,b),zero);
               else
                  *ans = nonnegval(FUNCTOR(b),ARG(0,b));
               return 0;
             }
          if(ZERO(b) && ARITY(a)==1  && FUNCTOR(a) != IMAGPART && FUNCTOR(a) != REALPART)
             { if(FUNCTOR(a)=='-')
                  *ans = le(zero,ARG(0,a));
               else
                  *ans = nonposval(FUNCTOR(a),ARG(0,a));
               return 0;
             }
          break;

       case'=':
          if(ATOMIC(a) && ATOMIC(b))
             { *ans = t;
               SET_ALREADY(*ans);
               return 0;
             }
          if(equals(a,b))
             { *ans = trueterm;
               return 0;
             }
          if(ZERO(a))
             { *ans = equation(b,a);  /* prefer x = 0 to 0 = x */
               return 0;
             }
          if(ZERO(b) && ARITY(a)==1  && FUNCTOR(a) != IMAGPART && FUNCTOR(a) != REALPART)
             { if(FUNCTOR(a)=='-')
                  *ans = equation(ARG(0,a),zero);
               else
                  *ans = zeroval(FUNCTOR(a),ARG(0,a));
               return 0;
             }
          break;
       case NE:
          if(ZERO(a) && FUNCTOR(b) == '*')
             { *ans = ne(b,zero);
               return 0;
             }
          if(ZERO(b) && FUNCTOR(a) == '*')
             { *ans = make_term(AND,ARITY(a));
               k=0;
               for(i=0;i<ARITY(a);i++)
                  { u = ARG(i,a);
                    if(NEGATIVE(u))
                       u = ARG(0,u);
                    if(ZERO(u))
                       { RELEASE(*ans);
                         *ans = falseterm;
                         return 0;
                       }
                    if(OBJECT(u))
                       continue;
                    u = lpt(ne(u,zero));
                    if(equals(u,falseterm))
                       { *ans =falseterm;
                         return 0;
                       }
                    if(!equals(u,trueterm))
                       { ARGREP(*ans,k,u);
                         ++k;
                       }
                  }
               if(k==0)
                  { RELEASE(*ans);
                    *ans = trueterm;
                    return 0;
                  }
               if(k==1)
                  { temp = ARG(0,*ans);
                    RELEASE(*ans);
                    *ans = temp;
                    return 0;
                  }
               SETFUNCTOR(*ans,AND,k);
               return 0;
             }

          if(ZERO(a) && ARITY(b)==1  &&
             FUNCTOR(b) != IMAGPART &&
             FUNCTOR(b) != REALPART
            )
             { unsigned short hh = FUNCTOR(b);
               if(hh =='-')
                  { *ans = ne(zero,ARG(0,b));
                    return 0;
                  }
               else if(ATOMIC(ARG(0,b)))
                  { *ans = nonzeroval(FUNCTOR(b),ARG(0,b));
                    if(immediate(*ans) == 1)
                       { *ans = trueterm;
                         return 0;
                       }
                    else
                       return 0;
                  }
               else if(!(hh==SIN || hh==COS || hh==TAN || h==COT) ||
                       !too_complicated(ARG(0,b))
                      )
                  { *ans = nonzeroval(hh,ARG(0,b));
                    return 0;
                  }
             }
          if(ZERO(b) && ARITY(a)==1  &&
             FUNCTOR(a) != IMAGPART &&
             FUNCTOR(a) != REALPART
            )
             { if(FUNCTOR(a)=='-')
                  { *ans = ne(ARG(0,a),zero);
                    return 0;
                  }
               else if(ATOMIC(ARG(0,a)))
                  { *ans = nonzeroval(FUNCTOR(a),ARG(0,a));
                    if(immediate(*ans) == 1)
                       { *ans = trueterm;
                         return 0;
                       }
                    else
                       { SET_ALREADY(*ans);
                         return 0;
                       }
                  }
               else
                  break;
             }
          if(FUNCTOR(a)==VECTOR)
             { assert(FUNCTOR(b)==VECTOR && ARITY(a)==ARITY(b));
               *ans = make_term(OR,ARITY(a));
               for(i=0;i<ARITY(a);i++)
                  ARGREP(*ans,i,ne(ARG(i,a),ARG(i,b)));
               return 0;
             }
          break;
     }
  if((f == '<' || f == LE) && ZERO(a) && !ATOMIC(b) && ARITY(b) == 1)
     { term u = ARG(0,b);
       double zz;
       if(seminumerical(u))
          { err = deval(b,&zz);
            if((!err && (zz > VERYSMALL && f == '<')) || ((zz > -VERYSMALL && f==LE)))
                { *ans = trueterm;
                  return 0;
                }
          }
       if(contains(u,FUNCTOR(pi_term)) &&
          (h==SIN || h==COS || h==TAN || h==COT || h==SEC || h==CSC)
         )
          { term temp;
            err = periodic(b,&temp);
            if(!err)
               { if(seminumerical(temp))
                    { err = deval(temp,&zz);
                      if((!err && (zz > VERYSMALL && f == '<')) || ((zz > -VERYSMALL && f==LE)))
                          { *ans = trueterm;
                            return 0;
                          }
                    }
                 *ans = f==LE ? le(zero,temp) : lessthan(zero,temp);
                 return 0;
               }
          }
       *ans =  f== '<' ? posval(FUNCTOR(b),ARG(0,b)) :
                          nonnegval(FUNCTOR(b),ARG(0,b));
       return 0;
     }
  if(f == NE && ZERO(a) && !ATOMIC(b) && ARITY(b) == 1)
     /* e.g.  tan(u) != 0  */
     { term u = ARG(0,b);
       double zz;
       if(seminumerical(u))
          { err = deval(b,&zz);
            if(!err && fabs(zz) > VERYSMALL)
                { *ans = trueterm;
                  return 0;
                }
          }
       if(contains(u,FUNCTOR(pi_term)) &&
          (h==SIN || h==COS || h==TAN || h==COT || h==SEC || h==CSC)
         )
          { term temp;
            err = halfperiodic(b,&temp);
            if(!err)
               { if(seminumerical(temp))
                    { err = deval(temp,&zz);
                      if(!err && fabs(zz) > VERYSMALL)
                          { *ans = trueterm;
                            return 0;
                          }
                    }
                 *ans = ne(zero,temp);
                 return 0;
               }
          }
       *ans =  nonzeroval(FUNCTOR(b),ARG(0,b));
       return 0;
     }
  if(ZERO(a) && !ATOMIC(b) && FUNCTOR(b) == ROOT)
     { *ans = t;  /* in case rootinfo fails */
       return rootinfo(f,b,ans);
     }
  if(f==NE && ZERO(b) && !ATOMIC(a) && g == ROOT)
     { *ans = t;
       return rootinfo(NE,a,ans);
     }
  if(ZERO(a) && !ATOMIC(b) && FUNCTOR(b) == LOGB)
     { *ans = make_term(f,2);
       ARGREP(*ans,0,one);
       ARGREP(*ans,1,ARG(1,b));
       return 0;
     }
  x = get_eigenvariable();
  if(contains_binders(t))
     return 1;  /* can't do anything further if it contains integrals, limits, etc. */
  if(!solved(t,x))
     { err = solve_it(a,b,f,ans);  /* If it contains only one occurrence
            of the eigenvariable, or does not contain the eigenvariable
            but has only one occurrence of some other variable. */
       if(err && contains(t,FUNCTOR(x)))
          { term u = make_term(f,2);
            ARGREP(u,0,a);
            ARGREP(u,1,b);
            temp_inhibit(explicitdomain);
            stopcheck(); /* documented in prover.c */
            err = ssolve(u,x,ans); 
            if(!err && contains(*ans,MULTIPLICITY))
               *ans = strip_multiplicities(*ans);
            startcheck();
            temp_release(explicitdomain);
          }
       if(!err)
          { if(ATOMIC(*ans))
               return 0;  /* it could be true or false */
            a = ARG(0,*ans);
            b = ARG(1,*ans);
            if(
                (!ISATOM(a) || TYPE(a) != INTEGER || !seminumerical(b)) &&
                (!ISATOM(b) || TYPE(b) != INTEGER || !seminumerical(a))
              )
               SETPRIME(*ans);  /* don't process again;  this stops a loop
                             3x = -1 => x = -1/3 => 3x = -1 by cancelling 1/3 */
            return 0;
          }
     }
  if( f == NE &&       /* catch n != 3/2, etc.  */
      ISATOM(a) &&
      TYPE(a) == INTEGER &&
      seminumerical(b)
    )
     { err = deval(b,&z);
       if(!err && !nearint(z,&kk))
           { *ans = trueterm;
             return 0;
           }
     }
  if( (f == LE || f == '<') &&       /* catch  3/2 < n, etc.  */
      ISATOM(b) &&
      TYPE(b) == INTEGER &&
      seminumerical(a)
    )
     { err = deval(a,&z);
       if(!err && !nearint(z,&kk))
           { long c;
             if(z < 0.0)
                c = - (long) (-z);
             else
                { c = (long) z + 1;
                  if(c==0)  /* overflow,  z was the largest long */
                     { *ans = t;
                       return 1;  /* this will never happen in a million years */
                     }
                }
             *ans = le(make_int(c),b);
             return 0;
           }
     }
  if( (f == LE || f == '<') &&       /* catch  n < 3/2, etc.  */
      ISATOM(a) &&
      TYPE(a) == INTEGER &&
      seminumerical(b)
    )
     { err = deval(b,&z);
       if(!err && !nearint(z,&kk))
           { long c;
             if(z < 0.0)
                { c = (long) (-z) - 1;
                  if(c==0)  /* overflow,  z was the largest negative long */
                    { *ans = t;
                      return 1;  /* this will never happen in a million years */
                    }
                  c = -c;
                }
             else
                c = (long) z;
             *ans = le(a,make_int(c));
             return 0;
           }
     }
  err = reduce_trigsum(t,ans);
  if(!err)
     return 0;
  /* the following code reduces, for example, 2(q+1)! < (q+2)! to 2 < q+2 */
  if(
     (FUNCTOR(a) == FACTORIAL ||
      (FUNCTOR(a) == '*' && contains_at_toplevel(a,FACTORIAL))
     ) &&
     (FUNCTOR(b) == FACTORIAL ||
      (FUNCTOR(b) == '*' && contains_at_toplevel(b,FACTORIAL))
     )
    )
     { char buffer[DIMREASONBUFFER];
       term temp;
       err = cancelfactorial2(make_fraction(b,a),zero,&temp,buffer);
       if(!err)
          { if(FRACTION(temp))
               { *ans = make_term(f,2);
                 ARGREP(*ans,0,ARG(1,temp));
                 ARGREP(*ans,1,ARG(0,temp));
                 return 0;
               }
          }
     }
  *ans = t;
  /* Now we're going to fail */
  reset_heap(savenode);
  set_nvariables(nvars);
  set_nextdefn(savenextdefn);
  set_nvariables(nvariables);
  set_eigenvariable(saveeigen);
  set_nextassumption(savenextassumption);
  return 1;
}
/*_____________________________________________________________________*/
static int cancel_identical(unsigned short f, term a, term b, term *ans)
/* cancel identical terms from both sides of inequality  a f b if
possible; return 0 for success, 1 for failure. */
{ unsigned short m,n;
  term u,v;
  int i,j,k;
  if(FUNCTOR(a) == '+' && FUNCTOR(b) != '+')
     { n = ARITY(a);
       for(i=0;i<n;i++)
          { if(equals(ARG(i,a),b))
               { if(n==2)
                    u = ARG( (i==0 ? 1 : 0), a);
                 else
                    { u = make_term('+',(unsigned short)(n-1));
                      for(j=0;j<i;j++)
                         ARGREP(u,j,ARG(j,a));
                      for(j=i;j<n-1;j++)
                         ARGREP(u,j,ARG(j+1,a));
                    }
                 *ans = make_term(f,2);
                 ARGREP(*ans,0,u);
                 ARGREP(*ans,1,zero);
                 return 0;
               }
          }
     }
  if(FUNCTOR(a) != '+' && FUNCTOR(b) == '+')
     { n = ARITY(b);
       for(i=0;i<n;i++)
          { if (equals(ARG(i,b),a))
               { if(n==2)
                    u = ARG( (i==0 ? 1 : 0), b);
                 else
                    { u = make_term('+',(unsigned short)(n-1));
                      for(j=0;j<i;j++)
                         ARGREP(u,j,ARG(j,b));
                      for(j=i;j<n-1;j++)
                         ARGREP(u,j,ARG(j+1,b));
                    }
                 *ans = make_term(f,2);
                 ARGREP(*ans,0,zero);
                 ARGREP(*ans,1,u);
                 return 0;
               }
          }
     }
  if(FUNCTOR(a) == '+' && FUNCTOR(b) == '+')
     { n = ARITY(a);
       m = ARITY(b);
       for(i=0;i<n;i++)
          { for(k=0;k<m;k++)
               { if(equals(ARG(i,a),ARG(k,b)))
                    { if(n==2)
                         u = ARG( (i==0 ? 1 : 0), a);
                      else
                         { u = make_term('+',(unsigned short)(n-1));
                           for(j=0;j<i;j++)
                              ARGREP(u,j,ARG(j,a));
                           for(j=i;j<n-1;j++)
                              ARGREP(u,j,ARG(j+1,a));
                         }
                      if(m==2)
                          v = ARG( (k==0 ? 1 : 0), b);
                      else
                         { v = make_term('+',(unsigned short)(m-1));
                           for(j=0;j<k;j++)
                              ARGREP(v,j,ARG(j,b));
                           for(j=k;j<m-1;j++)
                              ARGREP(v,j,ARG(j+1,b));
                         }
                      *ans = make_term(f,2);
                      ARGREP(*ans,0,u);
                      ARGREP(*ans,1,v);
                      return 0;
                    }
               }
          }
    }
  if(equals(a,b))
    { if(f == '<')
         { *ans = falseterm;
           return 0;
         }
      if(f == LE)
         { *ans = trueterm;
           return 0;
         }
      if(f == NE)
         { *ans = falseterm;
           return 0;
         }
      if(f == '=')
         { *ans = trueterm;
           return 0;
         }
    }
  return 1;
}
/*__________________________________________________________________*/
static int reduce_fractional_ineq(unsigned short f, term a, term b, term *ans)
/* reduce the inequality a f b  and return the result in *ans */
/* Return 0 for success, 1 for failure */
/* f is <, LE, or NE or =  */

{ term u,v,temp,temp2,whichvar,ans1,ans2;
  int stoploop;
  int err2;
  if(f == '<' && ZERO(a) && FUNCTOR(b) == '/')
     { u = ARG(0,b);
       v = ARG(1,b);
       if(OBJECT(u))
          *ans = lessthan(zero,v);
       else if(OBJECT(v))
          *ans = lessthan(zero,u);
       else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
          *ans = lessthan(v,zero);
       else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
          *ans = lessthan(u,zero);
       else if(FUNCTOR(v) == '+' && FUNCTOR(u) == '+' &&
               ARITY(u) == 2 && ARITY(v) == 2
              )
          /*  0 < (a+b)/(a-b) iff 0 < b(a-b)  */
          /*  if one of a or b is constant this will avoid
              introducing disjunctions */
          { term a = ARG(0,u);
            term b = ARG(1,u);
            term c = ARG(0,v);
            term d = ARG(1,v);
            if(equals(a,c))
               { if(NEGATIVE(b) && equals(ARG(0,b),d))
                    *ans = lessthan(zero,product(d,sum(a,b)));
                 else if(NEGATIVE(d) && equals(ARG(0,d),b))
                    *ans = lessthan(zero,product(b,sum(a,d)));
                 else
                    *ans = lessthan(zero, product(sum(a,d),sum(a,b)));
               }
            else if(equals(b,c))
               { /* switch the roles of a and b */
                 if(NEGATIVE(a) && equals(ARG(0,a),d))
                    *ans = lessthan(zero,product(d,sum(a,b)));
                 else if(NEGATIVE(d) && equals(ARG(0,d),a))
                    *ans = lessthan(zero,product(a,sum(b,d)));
                 else
                    *ans = lessthan(zero,product(sum(b,d),sum(a,b)));
               }
            else
               { term v2,u2;
                 copy(v,&v2);  // don't create a term with duplicates in different subterms
                 copy(u,&u2);
                 *ans = or(
                         and(lessthan(zero,v),lessthan(zero,u)),
                         and(lessthan(v2,zero),lessthan(u2,zero))
                        );
               }

          }
       else
          { term v2,u2;
            copy(v,&v2);  // don't create a term with duplicates in different subterms
            copy(u,&u2);
            *ans = or(
                    and(lessthan(zero,v),lessthan(zero,u)),
                    and(lessthan(v2,zero),lessthan(u2,zero))
                   );
          }
       return 0;
     }

  if(ONE(a) && FRACTION(b) && f == LE)
     { u = ARG(0,b);
       v = ARG(1,b);
       if(FUNCTOR(v) == '+' && FUNCTOR(u) == '+' &&
          ARITY(u) == 2 && ARITY(v) == 2
         )
         /*  1 <= (a+b)/(a-b) iff 0 <= b(a-b)  */
         /*  if one of a or b is constant this will avoid
             introducing disjunctions */

         { term aa = ARG(0,u);
           term bb = ARG(1,u);
           term c = ARG(0,v);
           term d = ARG(1,v);
           if(equals(aa,c))
              { if(NEGATIVE(bb) && equals(ARG(0,bb),d))
                   *ans = le(zero,(OBJECT(d) ? sum(aa,bb) : product(d,sum(aa,bb))));
                else if(NEGATIVE(d) && equals(ARG(0,d),bb))
                   *ans = le(zero,(OBJECT(bb) ? sum(aa,d) : product(bb,sum(aa,d))));
                return 0;
              }

         }
     }
  if(f == LE && ZERO(a) && FUNCTOR(b) == '/')
     { u = ARG(0,b);
       v = ARG(1,b);
       if(OBJECT(u))
          *ans = lessthan(zero,v);
       else if(OBJECT(v))
          *ans = le(zero,u);
       else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
          *ans = lessthan(v,zero);
       else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
          *ans = le(u,zero);
       else
          *ans = or(
                    and(lessthan(zero,v),le(zero,u)),
                    and(lessthan(v,zero),le(u,zero))
                  );
       return 0;
     }
  if(f == '<' && ZERO(b) && FUNCTOR(a) == '/')
     { u = ARG(0,a);
       v = ARG(1,a);
       if(OBJECT(u))
          *ans = lessthan(v,zero);
       else if(OBJECT(v))
          *ans = lessthan(u,zero);
       else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
          *ans = lessthan(zero,v);
       else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
          *ans = lessthan(zero,u);
       else
          *ans = or(
                    and(lessthan(zero,v),lessthan(u,zero)),
                    and(lessthan(v,zero),lessthan(zero,u))
                  );
       return 0;
     }
  if(f == LE && ZERO(b) && FUNCTOR(a) == '/')
     { u = ARG(0,a);
       v = ARG(1,a);
       if(OBJECT(u))
          *ans = lessthan(v,zero);
       else if(OBJECT(v))
          *ans = le(u,zero);
       else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
          *ans = lessthan(zero,v);
       else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
          *ans = le(zero,u);
       else
          *ans = or(
                    and(lessthan(zero,v),le(u,zero)),
                    and(lessthan(v,zero),le(zero,u))
                  );
       return 0;
     }
  if((f == LE || f == '<') &&
     OBJECT(a) &&
     FRACTION(b) &&
     OBJECT(ARG(0,b)) &&
     !OBJECT(ARG(1,b))
    )
    /*  a < u/v  with a and u positive numbers */
    /*  example:   1 < 1/cos x => 0 < cos x < 1 */
     { u = ARG(0,b);
       v = ARG(1,b);
       temp = f == LE ? le(v,make_fraction(u,a)) : lessthan(v,make_fraction(u,a));
       *ans = and(lessthan(zero,v), temp);
       return 0;
     }
  if( f == NE && FUNCTOR(a) == '/' && ZERO(b))
     { u = ARG(0,a);
       if(obviously_nonzero(u))
          *ans = trueterm;
       else
          *ans = ne(u,zero);
           /* regardless of the denom; the denom need not be defined */
       return 0;
     }
  if( f == '=' && FUNCTOR(a) == '/' && ZERO(b))
     { u = ARG(0,a);
       v = ARG(1,a);
       if(OBJECT(u))
          *ans = and(equation(u,zero),ne(v,zero));
       else if(OBJECT(v))
          *ans = equation(u,zero);
       else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
          *ans = and(equation(ARG(0,u),zero),ne(v,zero));
       else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
          *ans = equation(u,zero);
       else
          { temp2 = domain(v);
            if(equals(temp2,trueterm))
               *ans = equation(u,zero);
            else
               *ans = and(temp2,equation(u,zero));
          }
       return 0;
     }
  if( f == NE && FUNCTOR(b) == '/' && ZERO(a))
     { u = ARG(0,b);
       v = ARG(1,b);
       if(OBJECT(u))
          *ans = and(ne(u,zero),ne(v,zero));
       else if(OBJECT(v))
          *ans = ne(u,zero);
       else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
          *ans = and(ne(u,zero),ne(v,zero));
       else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
          *ans = ne(u,zero);
       else
         { temp2 = domain(v);
           if(equals(temp2,trueterm))
              *ans = ne(u,zero);
           else
              *ans = and(temp2,ne(u,zero));
         }

       return 0;
     }
  if( f == '=' && FUNCTOR(b) == '/' && ZERO(a))
     { u = ARG(0,b);
       v = ARG(1,b);
       if(OBJECT(u))
          *ans = and(equation(u,zero),ne(v,zero));
       else if(OBJECT(v))
          *ans = equation(u,zero);
       else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
          *ans = and(equation(ARG(0,u),zero),ne(v,zero));
       else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
          *ans = equation(u,zero);
       else
          *ans = and(domain(v),equation(u,zero));
       return 0;
     }
  if( FUNCTOR(a) == '/' && FUNCTOR(b) == '/')
     { term p,q,p1,p2,q1,q2;  /* u/p  < v/q */
       u = ARG(0,a);
       p = ARG(1,a);
       v = ARG(0,b);
       q = ARG(1,b);
       p1 = obviously_positive(p) ? trueterm : lessthan(zero,p);
       if(equals(p,q))      /* comparing fractions with the same denominator */
                             /* u/p < v/p iff u<v and p > 0 */
          { temp = make_term(f,2);
            ARGREP(temp,0,u);
            ARGREP(temp,1,v);
            if (f == '=' || f == NE || immediate(p1)==1)  /* a common case, e.g.  p = 2 */
               { *ans = temp;
                 return 0;
               }
            if(f == '=' || f == NE)
               { *ans = and(ne(p,zero),temp);
                 return 0;
               }
            p2 = obviously_negative(p) ? trueterm : lessthan(p,zero);
            temp2 = make_term(f,2);
            ARGREP(temp,0,v);
            ARGREP(temp,1,u);
            if(equals(p1,trueterm))
               *ans = temp;
            else if(equals(p2,trueterm))
               *ans = temp2;
            else
               *ans = or(and(p1,temp),and(p2,temp2));
            return 0;
          }
       /* comparing fractions with different denominators */
       if(f == '=' || f == NE)
          { p2 = ne(p,zero);
            q2 = ne(q,zero);
            polyval(sum(product(q,u),tnegate(product(p,v))),&temp);
            if(FUNCTOR(temp) == '+' && ARITY(temp) == 2 && NEGATIVE(ARG(1,temp)))
               temp = f == '=' ? equation(ARG(0,temp),ARG(0,ARG(1,temp))) :
                                 ne(ARG(0,temp),ARG(0,ARG(1,temp)));
            else
               temp = f == '=' ? equation(temp,zero) : ne(temp,zero);
            *ans = and3(p2,q2,temp);
            return 0;
          }
       p2 = obviously_negative(p) ? trueterm : lessthan(p,zero);
       q1 = obviously_positive(q) ? trueterm : lessthan(zero,q);
       q2 = obviously_negative(q) ? trueterm : lessthan(q,zero);
       if(equals(p1,trueterm) && equals(q1,trueterm))
          { if(equals(u,v))
                { /* equal nums, positive denoms */
                  if(obviously_nonnegative(u))
                      { *ans = make_term(f,2);
                        ARGREP(*ans,0,q);
                        ARGREP(*ans,1,p);
                        return 0;
                      }
                   if(obviously_nonnegative(strongnegate(u)))
                      { *ans = make_term(f,2);
                        ARGREP(*ans,0,p);
                        ARGREP(*ans,1,q);
                        return 0;
                      }
                   temp = make_term(f,2);
                   ARGREP(temp,0,q);
                   ARGREP(temp,1,p);
                   temp2 = make_term(f,2);
                   ARGREP(temp,0,p);
                   ARGREP(temp,1,q);
                   *ans = or(and(le(zero,u),temp),and(le(u,zero),temp2));
                   return 0;
                 }
            /* positive denoms, unequal nums.  Cross-multiply */
            *ans = make_term(f,2);
            polyval(product(u,q),&temp);
            polyval(product(v,p),&temp2);
            ARGREP(*ans,0,temp);
            ARGREP(*ans,1,temp2);
            return 0;
          }
       else if(equals(p2,trueterm) && equals(q2,trueterm))
          { if(equals(u,v))
                { /* equal nums, negative denoms */
                  if(obviously_nonnegative(u))
                      { *ans = make_term(f,2);
                        ARGREP(*ans,0,p);
                        ARGREP(*ans,1,q);
                        return 0;
                      }
                   if(obviously_nonnegative(strongnegate(u)))
                      { *ans = make_term(f,2);
                        ARGREP(*ans,0,q);
                        ARGREP(*ans,1,p);
                        return 0;
                      }
                   temp = make_term(f,2);
                   ARGREP(temp,0,q);
                   ARGREP(temp,1,p);
                   temp2 = make_term(f,2);
                   ARGREP(temp,0,p);
                   ARGREP(temp,1,q);
                   *ans = or(and(le(zero,u),temp2),and(le(u,zero),temp));
                   return 0;
                 }
            /* negative denoms, unequal nums.  Cross-multiply */
            *ans = make_term(f,2);
            polyval(product(u,q),&temp);
            polyval(product(v,p),&temp2);
            ARGREP(*ans,0,temp2);
            ARGREP(*ans,1,temp);
            return 0;
          }

       else if(
               (equals(p1,trueterm) && equals(q2,trueterm)) ||
               (equals(p2,trueterm) && equals(q1,trueterm))
              )
          { /* denoms have opposite signs. Cross-multiply and change the sense */
            if(equals(u,v))
               { /* equal nums */
                 *ans = make_term(f,2);
                 ARGREP(*ans,0,p);
                 ARGREP(*ans,1,q);
                 return 0;
               }
            polyval(product(u,q),&temp);
            polyval(product(v,p),&temp2);
            *ans = make_term(f,2);
            ARGREP(*ans,0,temp2);
            ARGREP(*ans,1,temp);
            return 0;
          }
       else  /* can't determine the signs of the denoms */
          { polyval(product(u,q),&temp);
            polyval(product(v,p),&temp2);
            ans1 = make_term(f,2);
            ARGREP(ans1,0,temp);
            ARGREP(ans1,1,temp2);
            ans2 = make_term(f,2);
            copy(temp2,ARGPTR(ans2));
            copy(temp,ARGPTR(ans2)+1);  /* avoid creating a DAG */
            *ans = or(
                      and(or(and(p1,q1),and(p2,q2)),ans1),
                      and(or(and(p1,q2),and(p2,q1)),ans2)
                     );
            return 0;
          }
     }
  temp = lessthan(a,b);
  stoploop = get_whichvar(temp,&whichvar);
  RELEASE(temp);
  if( FUNCTOR(b) == '/' && FUNCTOR(a) != '/'       /*  a < u/v */
      && (stoploop || !already_solved(a,b,whichvar))   /* stop loops as on  n < 1/2 */
    )
    { term w;
      u = ARG(0,b);
      v = ARG(1,b);
      temp = make_term(f,2);
      if(
          (FUNCTOR(a) == '+'  && FUNCTOR(v) != '+') ||
          (FUNCTOR(v) == '+'  && FUNCTOR(a) != '+')
        )
         { err2 = mvpolymult2(a,v,&w);
           if(err2)
              w = product(a,v);
         }
      else
         w = product(a,v);
      ARGREP(temp,0,w);
      ARGREP(temp,1,u);
      if(f == '=' || f == NE)
         { *ans = and(ne(v,zero),temp);
           return 0;
         }
      temp2 = make_term(f,2);
      ARGREP(temp2,0,u);
      ARGREP(temp2,1,product(v,a));
      *ans = or(and(lessthan(zero,v),temp),and(lessthan(v,zero),temp2));
      return 0;
    }
  if( FUNCTOR(a) == '/' && FUNCTOR(b) != '/' &&      /*   u/v < b */
      (stoploop || !already_solved(a,b,whichvar))
    )
    { term w;
      u = ARG(0,a);
      v = ARG(1,a);
      temp = make_term(f,2);
      if(
         (FUNCTOR(b) == '+'  && FUNCTOR(v) != '+') ||
         (FUNCTOR(v)=='+' && FUNCTOR(b) != '+')
        )
         { err2 = mvpolymult2(v,b,&w);
           if(err2)
               w = product(v,b);
         }
      else
         w = product(v,b);
      ARGREP(temp,1,w);
      ARGREP(temp,0,u);
      if(f == '=')
         { *ans = temp;  /* no need to throw in v != 0 */
           return 0;
         }
      if(f == NE)
         { *ans = and(temp,ne(v,zero));
           return 0;
         }
      temp2 = make_term(f,2);
      ARGREP(temp2,1,u);
      ARGREP(temp2,0,w);
      *ans = or(and(lessthan(zero,v),temp),and(lessthan(v,zero),temp2));
      return 0;
    }
  return 1;
}
/*___________________________________________________________*/
int simple_bounds(term t, term *ans)
/*  return 0 if t is an inequality  (< or LE), or an interval_as_and
(example:  -1 < sin x < 1) that can be deduced
from simple bounds on standard functions (in that case *ans = true);
If t is a strict inequality and the corresponding non-strict
inequality can be deduced (as in cos x < 1) but the bound is sharp,
then return the corresponding NE term  (as cos x != 1).
return 1 for failure to simplify t. */

/* Also return 0, with *ans= falseterm, in case t can be
refuted based on simple bounds on standard functions, for example,
1 < sin x, or sin x < -1. */

{ term u,v,a,b;
  unsigned short f = FUNCTOR(t);
  unsigned short g,h;
  int err;
  double z;
  if(f != '<' && f != LE && f != NE && f != AND)
     return 1;
  u = ARG(0,t);
  v = ARG(1,t);
  if(interval_as_and(t))
     { a = ARG(0,u);
       b = ARG(1,v);
       f = FUNCTOR(ARG(1,u));
       g = FUNCTOR(ARG(0,t));
       h = FUNCTOR(ARG(1,t));
       if(f == COS || f == SIN)
          { if(equals(a,minusone) && ONE(b))
               { if(g == LE && h == LE)
                    { *ans = trueterm;
                      return 0;
                    }
                 if(g == '<' && h == LE)
                    { *ans = ne(ARG(1,u),minusone);
                      return 0;
                    }
                 if(g == LE && h == '<')
                    { *ans = ne(ARG(1,u),one);
                      return 0;
                    }
                 if(g == '<' && h == '<')
                    { if(f == SIN)
                         { *ans = ne(cos1(ARG(0,ARG(1,u))),zero);
                           return 0;  /* odd multiples of pi/2 */
                         }
                      if(f == COS)
                         { *ans = ne(sin1(ARG(0,ARG(1,u))),zero);
                           return 0;
                         }
                    }
               }
            else if(ONE(b) && !infer(lessthan(a,minusone)))
               { if(h == '<')
                    { *ans = trueterm;
                      return 0;
                    }
                 if(h == LE)
                    { *ans = v;
                      return 0;
                    }
               }
            else if(equals(a,minusone) && !infer(lessthan(one,b)))
               {  if(g == '<')
                     { *ans = trueterm;
                       return 0;
                     }
                  if(g == LE)
                     { *ans = u;
                       return 0;
                     }
               }
            else if(!infer(lessthan(one,b)) && !infer(lessthan(a,minusone)))
               { *ans = trueterm;
                 return 0;
               }
          }
       return 1;   /* added 1.4.00  */
     }
  if(f == AND)
     return 1;  /* not an interval_as_and */
  if(f == NE)
     { /* catch for example sin x != 4 and return true */
       if(get_complex())
          return 1;
       if(
          (FUNCTOR(u) == SIN || FUNCTOR(u) == COS) &&
          seminumerical(v)
         )
          { deval(v,&z);
            if(z == BADVAL)
               { if(OBJECT(v) && TYPE(v) == BIGNUM)
                   { *ans = trueterm;  /* very large number */
                     return 0;
                   }
                 return 1;  /* unknown causes, e.g. reciprocal of
                               a large bignum would get here */
               }
            if(fabs(z) > 1.0)
               { *ans = trueterm;  /* sin and cos bounded between -1 and 1 */
                 return 0;
               }
          }
        return 1;
      }
  /* Now f is LE or < */
  if(FRACTION(u) && FRACTION(v) && equals(ARG(1,u),ARG(1,v)) &&
     obviously_positive(ARG(1,u))
    )
     /* example,  sin^n(u)/2^n <= 1/2^n   */
     { u = ARG(0,u);
       v = ARG(0,v);
     }
  if(ZERO(u)) /* catch 0 <= 1+cos x etc */
     { err = inf(v,&u);
       if(err)
          return 1;
       if(ZERO(u))
          { *ans = f == LE ? trueterm : ne(v,zero);
            return 0;
          }
       err = infer(le(zero,u));
       if(err)
          return 1;
       if(f == LE)
          { *ans = trueterm;
            return 0;
          }
       /* Now f == '<' */
       err = infer(lessthan(zero,u));
       if(!err)
          { *ans = trueterm;
            return 0;
          }
       *ans = ne(v,zero);
       return 0;
     }
  if(constant(u) && !ATOMIC(v))
   /* lower bounds */
     { g = FUNCTOR(v);
       if(g == '^' && POSNUMBER(ARG(1,v)))
          /* handle sin^k x  >= -1 as well as sin x >= -1 */
          { v = ARG(0,v);
            g = FUNCTOR(v);
          }
       if((g == SEC || g == CSC) && !infer(le(u,one)))
          { if(f == '<' || !infer(lessthan(u,minusone)))
               { *ans = trueterm;
                 return 0;
               }
            return 1;
          }
       if((g == COS || g == SIN) && !infer(le(u,minusone)))
          { if(f == LE || !infer(lessthan(u,minusone)))
               { *ans = trueterm;
                 return 0;
               }
            if(equals(u,minusone))
               { *ans = ne(v,u);  /* -1 < sin x iff -1 != sin x; the latter is easier to solve */
                 return 0;
               }
            return 1;
          }
       if((g == COS || g == SIN) && !infer(le(one,u)))
          { if(ONE(u) && f == LE)
               { *ans = equation(v,u);    /* 1 <= sin x iff sin x == 1 */
                 return 0;
               }
            if(f == '<' || !infer(lessthan(one,u)))
               { *ans = falseterm;  /* refute 1 < cos x or 2 <= cos x */
                 return 0;
               }
          }
       return 1;
          /* -1 < cos a if a isn't an odd multiple of pi  */
          /* -1 < sin a if a+pi/2 isn't an even multiple of pi */
          /* These are too hard to express and look too complicated
             anyway, better to leave these inequalities alone. */

     }
  if(constant(v) && !ATOMIC(u))
    /* upper bounds */
     { g = FUNCTOR(u);
       if(g == '^' && POSNUMBER(ARG(1,u)))
          /* handle sin^k x  >= -1 as well as sin x >= -1 */
          { u = ARG(0,u);
            g = FUNCTOR(u);
          }
       if(g != COS && g != SIN)
          return 1;
       if(ONE(v) && f == LE)
          { *ans = trueterm;
            return 0;
          }
       if(ONE(v) && f == '<')
          { *ans = ne(v,one);
             return 0;
          }
       err = infer(le(one,v));
       if(err)
          return 1;
       if(f == LE)
          { *ans = trueterm;   /* cos a \le 1 */
            return 0;
          }
       err = infer(lessthan(one,v));
       if(!err)
          { *ans = trueterm;
            return 0;
          }
       return 1;  /* give up, inequality too complicated */
     }
  if(FUNCTOR(u) == SIN && equals(v,ARG(0,u)) && obviously_nonnegative(v))
     { if(f == LE)
          { *ans = trueterm;
            return 0;
          }
       if(obviously_positive(v))
          { *ans = trueterm;
            return 0;
          }
       *ans = ne(v,zero);
       return 0;
     }
  if(f == '<' && FUNCTOR(u) == SIN && equals(v,ARG(0,u)) && obviously_positive(v))
     { *ans = trueterm;
        return 0;
     }
  return 1;
}
/*___________________________________________________________________*/
static int solve_it(term leftside, term rightside, unsigned short f, term *ans)
/* determine variable v:  the eigenvariable if leftside or rightside
contains it, otherwise, the unique variable in leftside = rightside if there
is only one; else fail.  Then if v occurs on only one side of the
equation, try to solve it using invert_ineq or other methods.
Return 0 for success, 1 for failure.
f is the functor of the 'equation', which can be NE or an inequality
as well as =.
If the equation is already solved, so that *ans would be the
original equation, that counts as failure.
Always return a solved inequality with functor < or LE, not > or GE.
But a solved equation can have the variable on either side.
*/

{ term v = get_eigenvariable();
  int nvariables = get_nvariables();
  term *varlist = get_varlist();
  term temp;
  int l,r,ll,rr,i,err,count=0;
  l = contains(leftside,FUNCTOR(v));
  r = contains(rightside,FUNCTOR(v));
  if(l && r)
     return 1;
  if(!l && !r)  /* look for a unique v */
    { for(i=0;i<nvariables;i++)
        { temp = varlist[i];
          ll = contains(leftside,FUNCTOR(temp));
          rr = contains(rightside,FUNCTOR(temp));
          if(ll && rr)
             return 1;  /* some variable on both sides */
          if(ll || rr)
              { ++count;
                v = temp;
                l = ll;  /* record which side we found v on */
                r = rr;
              }
        }
      if(count != 1)
         return 1;   /* no variable, or two or more variables */

    }
  if(l)
     { if(equals(leftside,v))
          return 1;   /* already solved */
       if(f == '=' || f == NE)
          err = invert_eqn(leftside,rightside,v,&temp);
       else
          err = invert_ineq(leftside,rightside,v,&temp,&f);
       if(err < 0 && f== '=')  /* impossible equation */
         { *ans = falseterm;
           return 0;
         }
       if(err < 0 && f== NE)  /* impossible equation is valid NE*/
         { *ans = trueterm;
           return 0;
         }
       if(!err)
         { *ans = make_term(f,2);
           ARGREP(*ans,0,v);
           ARGREP(*ans,1,temp);
           goto success;
         }
       return 1;
     }
  else if(r)
     { if(equals(rightside,v))
          return 1;   /* already solved */
       if(f == '=' || f == NE)
          err = invert_eqn(rightside,leftside,v,&temp);
       else
          { f = SWITCH(f);
            err = invert_ineq(rightside,leftside,v,&temp,&f);
          }
       if(err < 0 && f== '=')  /* impossible equation */
          { *ans = falseterm;
            return 0;
          }
       if(err < 0 && f== NE)  /* impossible equation is valid NE*/
          { *ans = trueterm;
            return 0;
          }
       if(!err)
          { if(f == '>' || f == GE)
               { *ans = make_term(SWITCH(f),2);
                 ARGREP(*ans,1,v);
                 ARGREP(*ans,0,temp);
                 goto success;
               }
            *ans = make_term(f,2);
            ARGREP(*ans,0,v);
            ARGREP(*ans,1,temp);
            goto success;
          }
       return 1;
     }
   assert(0);  /* either l or r was nonzero */
   success:
   if(get_binders() == NULL)
      SETPRIME(*ans);
   else
      { term h,a,q;
        err = get_infinitesimal(&h,&a,&q);
        if(!err && !contains(*ans,FUNCTOR(h)))
           SETPRIME(*ans);
      }
   if(FUNCTOR(*ans) == '>')
      *ans = lessthan(ARG(1,*ans),ARG(0,*ans));
   else if(FUNCTOR(*ans) == GE)
      *ans = le(ARG(1,*ans),ARG(0,*ans));
   return 0;
}
/*_________________________________________________________________________*/
static int one_sign(term a)
/* a is a sum. Return 1 if all the summands are nonnegative and at least
one positive number is among them.
   Also a sum of the form x + sqrt(x^2 + positive) is positive.
   Return -1 if all are nonpositive and at
least one negative number is among them.
   Return 0 otherwise (can't prove the function is all of one sign this way)
    For speed, and to avoid creating new variables by analyzing trig
functions, this function applies only limited tests for positivity to
the summands.  */


{ int flag = 0;
  int err,i,sign;
  term u,v,p,q;
  double z;
  unsigned short n = ARITY(a);
  if(n==2)
     { // check for the special case x + sqrt(x^2+positive) 
       if(FUNCTOR(ARG(0,a)) == SQRT || FUNCTOR(ARG(0,a)) == '^')
        { u = ARG(1,a);
          v = ARG(0,a);
        }
       else
          {  u = ARG(0,a);
             v = ARG(1,a);
          }
       if(
           (FUNCTOR(v) == SQRT && FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2) ||
           (FUNCTOR(v) == '^' && equals(ARG(1,v),make_fraction(one,two)) && FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2)
         )
          { p = ARG(0,ARG(0,v));
            q = ARG(1,ARG(0,v));
            if(FUNCTOR(p) == '^' && equals(ARG(1,p),two) && equals(ARG(0,p),u) && !infer(lessthan(zero,q)))
                 return 1;
            if(FUNCTOR(q) == '^' && equals(ARG(1,q),two) && equals(ARG(0,q),u) && !infer(lessthan(zero,p)))
                 return 1;
          }
       }
  if(n==2 && (NEGATIVE(ARG(1,a)) || NEGATIVE(ARG(0,a))))
     { // check for the special case x - sqrt(x^2+positive) (which is negative, so -1 will be returned)
       if(NEGATIVE(ARG(1,a)))
           { v = ARG(0,ARG(1,a));
             u = ARG(0,a);
           }
        else 
           { u = ARG(0,ARG(0,a));
             v = ARG(1,a);
           }          
        if(
           (FUNCTOR(v) == SQRT && FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2) ||
           (FUNCTOR(v) == '^' && equals(ARG(1,v),make_fraction(one,two)) && FUNCTOR(ARG(0,v)) == '+' &&  ARITY(ARG(0,v)) == 2)
         )
          { p = ARG(0,ARG(0,v));
            q = ARG(1,ARG(0,v));
            if(FUNCTOR(p) == '^' && equals(ARG(1,p),two) && equals(ARG(0,p),u) && !infer(lessthan(zero,q)))
                 return -1;
            if(FUNCTOR(q) == '^' && equals(ARG(1,q),two) && equals(ARG(0,q),u) && !infer(lessthan(zero,p)))
                 return -1;
          }
       }
  for(i=0;i<n;i++)
     { u = ARG(i,a);
       if(OBJECT(u) && !ZERO(u))
          { if(flag < 0)
               return 0;  /* both neg and pos terms */
            flag = 1;
          }
       else if(FUNCTOR(u)=='-' && OBJECT(ARG(0,u)))
          { if(flag > 0)
               return 0;
            flag = -1;
          }
       else if(seminumerical(u) && !deval(u,&z) && z != BADVAL)
          { /* example, u = sqrt(3) */
            if(z > 0.0)
               { if(flag < 0)
                    return 1;
                 flag = 1;
               }
            else if(z < 0.0)
               { if(flag > 0)
                    return 1;
                 flag = -1;
               }
          }
      }
   if(flag==0)
      return 0;   /* no seminumerical term present, failure */
   if(n == 2 && (contains(a,SIN) || contains(a,COS)))
      /* catch  sin x - 1 etc  */
      { p = ARG(0,a);
        q = ARG(1,a);
        if(FUNCTOR(p) == COS || FUNCTOR(p) == SIN)
           { err = deval(q,&z);
             if(!err)
                { if(z > 1.0)
                     return 1;
                  if(z < -1.0)
                     return -1;
                }
           }
        else if(FUNCTOR(q) == COS || FUNCTOR(q) == SIN)
           { err = deval(p,&z);
             if(!err)
                { if(z > 1.0)
                     return 1;
                  if(z < -1.0)
                     return -1;
                }
           }
      }
   for(i=0;i<n;i++)
      { u = ARG(i,a);
        if(OBJECT(u) || (FUNCTOR(u)=='-' && OBJECT(ARG(0,u))))
           continue;
        sign = easy_sign(u);  /* 1 or -1 if sign can be determined */
        if(sign != flag)
           return 0;
      }
   return flag;
}
/*____________________________________________________________________*/
static int easy_sign(term t)
/* return 1 if t is obviously nonnegative, -1 if obviously
negative, 0 if can't easily tell.  */

{ unsigned short n;
  int sign,sign2,i;
  if(ISATOM(t))
     { if(equals(t,eulere) || equals(t,pi_term))
          return 1;
       return 0;
     }
  if(OBJECT(t))
     return 1;
  if(FUNCTOR(t) == '+')
     return one_sign(t);
  if(FUNCTOR(t) == SQRT)
     return 1;
  if(FUNCTOR(t) == ROOT && iseven(ARG(0,t)))
     return 1;
  if(NEGATIVE(t))
     return -easy_sign(ARG(0,t));
  if(FRACTION(t))
     { if(OBJECT(ARG(1,t)))
          return easy_sign(ARG(0,t));
       if(OBJECT(ARG(0,t)))
          return easy_sign(ARG(1,t));
       sign = easy_sign(ARG(0,t));
       if(!sign)
          return 0;  /* failure */
       sign2 = easy_sign(ARG(1,t));
       if(!sign2)
          return 0;
       return sign * sign2;
     }
  if(FUNCTOR(t) == '^')
     { if(iseven(ARG(1,t)))
           return 1;
       return 0;
     }
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       sign = 1;
       for(i=0;i<n;i++)
          { sign *= easy_sign(ARG(i,t));
            if(!sign)
               return 0;
          }
       return sign;
     }
  return 0;
}

/*___________________________________________________________________*/
int isdifofsquares(term t)
/* return 1 if t has the form a^2-b^2 or  -a^2 + b^2,
or a^2-1 or -1 + a^2. Else return 0  */
{ term u,v;
  if(FUNCTOR(t) != '+' || ARITY(t) != 2)
      return 0;
  u = ARG(0,t);
  v = ARG(1,t);
  if(NEGATIVE(u) && NEGATIVE(v))
     return 0;   /* just ONE of them must be negative */
  if(NEGATIVE(u))
     u = ARG(0,u);
  else if(NEGATIVE(v))
     v = ARG(0,v);
  else
     return 0;
  if(ONE(u) && FUNCTOR(v) == '^' && equals(ARG(1,v),two))
     return 1;
  if(ONE(v) && FUNCTOR(u) == '!' && equals(ARG(1,u),two))
     return 1;
  if(FUNCTOR(u) != '^' || !equals(ARG(1,u),two))
     return 0;
  if(FUNCTOR(v) != '^' || !equals(ARG(1,v),two))
     return 0;
  return 1;
}
/*______________________________________________________________*/
static int reduce_trigsum(term t, term *ans)
/* reduce cos x <= 1 + sin x  to cos x <= 0 or 0 <= sin x,
   and reduce  -1-sin x <= cos x to  0 <= sin x or 0 <= cos x,
   and reduce  cos x - sin x <= 1
   and reduce -1 <= cos x + sin x
   and similarly for strict inequalities.  Put the answer in *ans.
   Return 0 for success, 1 for failure; in case of failure,
   *ans is garbage.
*/
{ term a,b,u,v,x;
  unsigned short f,g,h;
  f = FUNCTOR(t);
  assert(ARITY(t)==2);
  if(f != '<' && f != LE)
     return 1;
  if(PRIME(t))
      return 1;   /* already processed */
  a = ARG(0,t);
  b = ARG(1,t);
  g = FUNCTOR(a);
  h = FUNCTOR(b);
  if(g == COS)
     { x = ARG(0,a);
       if(h != '+' || ARITY(b) != 2)
          return 1;
       u = ARG(0,b);
       v = ARG(1,b);
       if(ONE(v))
          { v = u;
            u = one;
          }
       if(ONE(u) && FUNCTOR(v) == SIN && equals(ARG(0,v),x))
          { /* cos x <= 1 + sin x */
            *ans = f == LE ?
               or(le(cos1(x),zero),le(zero,sin1(x))) :
               or(lessthan(cos1(x),zero),lessthan(zero,sin1(x)));
            return 0;
          }
       return 1;
     }
  if(h == COS)
     { x = ARG(0,b);
       if(g != '+' || ARITY(a) != 2)
          return 1;
       u = ARG(0,a);
       v = ARG(1,a);
       if(!NEGATIVE(u))
          return 1;
       u = ARG(0,u);
       if(!NEGATIVE(v))
          return 1;
       v = ARG(0,v);
       if(ONE(v))
          { v = u;
            u = one;
          }
       if(ONE(u) && FUNCTOR(v) == SIN && equals(ARG(0,v),x))
          { /* -1-sin x <= cos x */
            *ans = f == LE ?
               or(le(zero,cos1(x)),le(zero,sin1(x))) :
               or(lessthan(zero,cos1(x)),lessthan(zero,sin1(x)));
            return 0;
          }
       return 1;
     }
  if(ONE(b) && g == '+' && ARITY(a) == 2 && NEGATIVE(ARG(1,a)))
     { u = ARG(0,a);
       v = ARG(1,ARG(1,a));
       if(FUNCTOR(u) == COS && FUNCTOR(v) == SIN && equals(ARG(0,u),ARG(0,v)))
          { x = ARG(0,u);
            *ans = f == LE ?
               or(le(cos1(x),zero),le(zero,sin1(x))) :
               or(lessthan(cos1(x),zero),lessthan(zero,sin1(x)));
            return 0;
          }
       return 1;
     }
  if(equals(a,minusone) && FUNCTOR(b) == '+' && ARITY(b) == 2)
     { u = ARG(0,b);
       v = ARG(1,b);
       if(
          (
           (FUNCTOR(u) == COS && FUNCTOR(v) == SIN) ||
           (FUNCTOR(v) == COS && FUNCTOR(u) == SIN)
          ) &&
          equals(ARG(0,u),ARG(0,v))
         )
          { x = ARG(0,u);
            *ans = f == LE ?
               or(le(zero,cos1(x)),le(zero,sin1(x))) :
               or(lessthan(zero,cos1(x)),lessthan(zero,sin1(x)));
            return 0;
          }
       return 1;
     }
  return 1;
}

/*__________________________________________________________________*/
static int contains_binders(term t)
/* return 1 if t contains a binding functor */

{ unsigned short n,f;
  int i;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if(f == INTEGRAL || f == LIMIT || f == DIFF || f == LIMIT ||
     f == SUM || f == PRODUCT
    )
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_binders(ARG(i,t)))
          return 1;
     }
  return 0;
}

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