Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/algebra/
Upload File :
Current File : /usr/home/beeson/MathXpert/algebra/ineq2.c

/* M. Beeson for MathXpert
   some inequality operators

Original date 7.12.92
Last modified 6.14.98
2.29.00 removed pragma argsused
5.6.13 changed search.h to stdlib.h
5.6.13 made special() static.  
*/

#include "globals.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>

#include "ops.h"
#include "operator.h"
#include "probtype.h"
#include "prover.h"
#include "deval.h"
#include "symbols.h"
#include "errbuf.h"
#include "pvalaux.h"  /* topflatten */
#include "ssolve.h"   /* solved     */
#include "eqn.h"      /* econstant  */
#include "autosimp.h" /* SetShowStepArg */

static term reverse(term t);
static int special( const void *a, const void *b);
/*_______________________________________________________________________

Remarks on logic and computation.  The relation between logic and computation
is different for different problem types.

When solving inequalities, if A is the original inequality, Gamma the
assumptions depending on the eigenvariable, Delta the assumptions involving
only parameters, B the current line, we have

       dom(A), Delta => A <-->(B,Gamma)

which is stronger than what we demand for simplification:

       dom(A), Delta, Gamma => A <-->B

or for equation-solving:

       dom(A), Delta => A -> (B,Gamma)
In the latter case when we find solutions of (B,Gamma), we can check them
to see if they are solutions of A also, and we will know we have not
omitted any because A -> (B,Gamma) without any eigenvalue-dependent assumptions.

In these terms, this operation replaces B by (B,Gamma) so the property
above will be maintained.  Of course, the lower property is maintained too,
but it is insufficient to claim the inequality is solved.
_________________________________________________________________________*/

static term eliminate_ne(term t);
/*_______________________________________________________________*/
static int extract_constant(term t, term *ans, double *val)
/* if t has the form (x-c) set *ans =c, and *val the decimal value
of c; if it fails to have a decimal value return 1. Return 0 for success. */
/* Used below in intervals_aux */
{ term x;
  int i,err,flag=0,place;
  unsigned short n;
  if(FUNCTOR(t) != '+')
     return 1;
  x = get_eigenvariable();
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(equals(ARG(i,t),x))
          { ++flag;
            place = i;
          }
     }
  if(flag != 1)
     return 1;
  if(n==2)
     { tneg(ARG((place ? 0 : 1),t),ans);
       err = deval(*ans,val);
       return err;
     }
  /* now n>2, possible e.g. for (x-\pi -1)  */
  *ans = make_term('+',(unsigned short)(n-1));
  for(i=0;i<place;i++)
     ARGREP(*ans,i,tnegate(ARG(i,t)));
  for(i=place+1;i<n;i++)
     ARGREP(*ans,i-1,tnegate(ARG(i,t)));
  err = deval(*ans,val);
  if(err)
     { RELEASE(*ans);
       return 1;
     }
  return 0;
}
/*_______________________________________________________________*/
struct sp { term c;
            int odd;
            double val;
            int protect;
          };
/*________________________________________________________________*/
static int special( const void *a, const void *b)
/* comparison function for a special application of qsort in the
next function. */
{ if(((struct sp *) a)->val < ((struct sp *)b)->val)
     return -1;
  if(((struct sp *)b)->val < ((struct sp *) a)->val)
     return 1;
  return 0;
}
/*_______________________________________________________________*/
static int intervals_aux(term t, unsigned short f, term *pos, term *neg)
/* t is a product, f is '<' or LE.  First check that every factor
of t has the form (x-a), or a power of such factors; and the
form x standing alone is allowed too, the same as (x-0).
(If not, return 1.)  Then determine, if possible,
disjunctions of intervals (or an interval) on which f is positive
(negative) and return them in *pos and *neg, signalling success
with a zero return value.  Nonzero return is failure.  Adjacent
intervals are not combined; that is you can get or( 0 <= x <= 1, 1 <= x <= 2)
as an answer, after which combineintervals will be applied in the next step.
*/

/* The way this works is this:  we first build an array of object
of type struct sp. Then we sort this array using the comparison function
'special' constructed above. Then we build from the sorted array the
desired disjunction of intervals. */

{ int err;
  term interval,temp;
  unsigned short p,q,count;
  unsigned short n = ARITY(t);
  double v;
  term x,u;
  int i;
  struct sp *points;
  x = get_eigenvariable();
  points = (struct sp *) callocate(n,sizeof(struct sp));
  if(points == NULL)
     { nospace();
       return 1;
     }
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       points[i].protect = PROTECTED(u) ? 1 : 0;
       if(equals(u,x))
         { points[i].c = zero;
           points[i].val = 0.0;
           points[i].odd = 1;
         }
       else if(FUNCTOR(u) != '^' && FUNCTOR(u) != '+')
           return 1;
       else if(FUNCTOR(u) == '^')
         { err = infer(even(ARG(1,u)));
           if(err)
              { err = infer(odd(ARG(1,u)));
                if(err)
                   { free2(points);
                     return 1;  /* can't determine sign of exponent */
                   }
                if(equals(ARG(0,u),x))
                   { temp = zero;
                     v = 0.0;
                   }
                else
                   { err = extract_constant(ARG(0,u),&temp,&v); /* exponent is odd */
                     if(err)
                        { free2(points);
                          return 1;
                        }
                   }
                if(points[i].protect)
                   PROTECT(temp);
                points[i].c = temp;
                points[i].odd = 1;
                points[i].val = v;
              }
           else  /* exponent is even */
              {
                if(equals(ARG(0,u),x))
                   { temp = zero;
                     v = 0.0;
                   }
                else
                   { err = extract_constant(ARG(0,u),&temp,&v);
                     if(err)
                        {  free2(points);
                           return 1;
                        }
                   }
                if(points[i].protect)
                   PROTECT(temp);
                points[i].c = temp;
                points[i].odd = 0;
                points[i].val = v;
              }
         }
       else  /* this term not a power */
         { err = extract_constant(u,&temp,&v);
           if(err)
              { free2(points);
                return 1;
              }
           if(points[i].protect)
              PROTECT(temp);
           points[i].c = temp;
           points[i].odd = 1;
           points[i].val = v;
         }
     }
   qsort(points,n,sizeof(struct sp),special);
   /* Now 'points' is sorted; build *pos and *neg */
   *pos = make_term(OR,(unsigned short)(n+1));
   *neg = make_term(OR,(unsigned short)(n+1));
   p = q = 0;  /* p counts the terms put into pos, q into neg */
   count = 0;  /* let's count the total number of sign changes */
   for(i=0;i<n;i++)
      { if(points[i].odd)
           ++count;
      }
   /* Now the leftmost sign is negative if count is odd, positive if even */
   i=0;
   if(f == '<')
      interval =lessthan(x,points[0].c);
   else  /* for <= skip initial even roots */
      { while(points[i].odd == 0 && i < n) ++i;
        if(i==n)
           { // all roots were even, so the function is non-negative or non-positive
             if(count & 1)
                { // function is nonpositive
                  *neg = trueterm;
                  *pos = falseterm;
                  return 0;
                }
             else
                { *pos = trueterm;
                  *neg = falseterm;
                }
             return 0;
           }    
        interval = le(x,points[i].c);
      }
   if(count & 1)  /* an odd number of odd roots so first interval is neg */
      { ARGREP(*neg,q,interval);
        ++q;
        count = 1;   /* last one went into neg */
      }
   else   /* even number of odd roots so first interval is pos */
      { ARGREP(*pos,p,interval);
        ++p;
        count = 0;   /* last one went into pos */
      }
   ++i;       /* so i=1 if there were no initial even points, or if f == '<' */
   for(;i<n;i++)  /* i is already initialized */
      { if(f == '<')
           interval = and(lessthan(points[i-1].c,x),lessthan(x,points[i].c));
        else if(i<n)
           interval = and(le(points[i-1].c,x),le(x,points[i].c));
        else
           interval = le(points[i-1].c,x);
        if (points[i-1].odd)  /* a sign change */
            { if(count == 1)  /* last one went into neg */
                 { ARGREP(*pos,p,interval);
                   ++p;
                 }
              else
                 { ARGREP(*neg,q,interval);
                   ++q;
                 }
              count = (unsigned short)(count ? 0 : 1);
            }
         else  /* not a sign change */
            { if(count)  /* last one went into neg, put this one there too */
                 { ARGREP(*neg,q,interval);
                   ++q;
                   if(f==LE)  /* put one point into *pos */
                      { ARGREP(*pos,p,equation(x,points[i-1].c));
                        ++p;
                      }
                 }
               else
                 { ARGREP(*pos,p,interval);
                   ++p;
                   if(f==LE)  /* put one point into *neg */
                      { ARGREP(*neg,q,equation(x,points[i-1].c));
                        ++q;
                      }
                 }
                 /* and count doesn't change */
            }
      }
   /* Now for the very last interval  (unless last root was even and it's <=,
      not <, in which case we got it already) */

   if(points[n-1].odd || f == '<')
      { interval = f == LE ? le(points[n-1].c,x) : lessthan(points[n-1].c,x);
        ARGREP(*pos,p,interval);  /* it's always positive */
        ++p;
      }
   SETFUNCTOR(*pos,OR,p);
   SETFUNCTOR(*neg,OR,q);
   if(q==1)
      { temp = ARG(0,*neg);
        RELEASE(*neg);
        *neg = temp;
      }
   if(p==1)
      { temp = ARG(0,*pos);
        RELEASE(*pos);
        *pos = temp;
      }
   return 0;
}
/*_______________________________________________________________*/
int intervalsneg1(term ineq, term arg, term *next, char *reason)
/* ineq is t < 0, where t must be a product of terms of the form (x-a).
The various a's must be all numbers, or at least their pairwise
differences must all be numbers, so that they can be ordered correctly.
*next is then returned as an interval or a disjunction of intervals
on which t is negative.  */

{ int err;
  unsigned short f = FUNCTOR(ineq);
  term pos,neg,left,right;
  if(f != '<' && f != '>')
     return 1;
  left = f == '<' ? ARG(0,ineq) : ARG(1,ineq);
  right = f == '<' ? ARG(1,ineq) : ARG(0,ineq);
  if(!ZERO(right))
     return 1;
  if(FUNCTOR(left) != '*')
     return 1;
  err = intervals_aux(left,'<',&pos,&neg);
  if(err)
     return 1;
  if(f == '<')
     *next = neg;
  else
     *next = reverse(neg);
  HIGHLIGHT(*next);
  strcpy(reason,english(487)); /* examine the signs         of the factors */
  return 0;
 }

/*_______________________________________________________________*/
int intervalspos1(term ineq, term arg, term *next, char *reason)
/* like intervalsneg1 except ineq is 0 < t
*/
{ int err;
  unsigned short f = FUNCTOR(ineq);
  term pos,neg,left,right;
  if(f != '<' && f != '>')
     return 1;
  left = f == '<' ? ARG(0,ineq) : ARG(1,ineq);
  right = f == '<' ? ARG(1,ineq) : ARG(0,ineq);
  if(!ZERO(left))
     return 1;
  if(FUNCTOR(right) != '*')
     return 1;
  err = intervals_aux(right,'<',&pos,&neg);
  if(err)
     return 1;
  if(f == '<')
     *next = pos;
  else
     *next = reverse(pos);
  HIGHLIGHT(*next);
  strcpy(reason,english(487)); /* examine the signs         of the factors */
  return 0;
 }

/*_______________________________________________________________*/
int intervalsneg2(term ineq, term arg, term *next, char *reason)
/* like intervalsneg1 except ineq is t \le 0 */
{ int err;
  unsigned short f = FUNCTOR(ineq);
  term pos,neg,left,right;
  if(f != LE && f != GE)
     return 1;
  left = f == LE ? ARG(0,ineq) : ARG(1,ineq);
  right = f == LE ? ARG(1,ineq) : ARG(0,ineq);
  if(!ZERO(right))
     return 1;
  if(FUNCTOR(left) != '*')
     return 1;
  err = intervals_aux(left,LE,&pos,&neg);
  if(err)
     return 1;
  if(f == LE)
     *next = neg;
  else
     *next = reverse(neg);
  HIGHLIGHT(*next);
  strcpy(reason,english(487)); /* examine the signs         of the factors */
  return 0;
 }

/*_______________________________________________________________*/
int intervalspos2(term ineq, term arg, term *next, char *reason)
/* like intervalsneg2 except ineq is 0<=t */
{ int err;
  unsigned short f = FUNCTOR(ineq);
  term pos,neg,left,right;
  if(f != LE && f != GE)
     return 1;
  left = f == LE ? ARG(0,ineq) : ARG(1,ineq);
  right = f == LE ? ARG(1,ineq) : ARG(0,ineq);
  if(!ZERO(left))
     return 1;
  if(FUNCTOR(right) != '*')
     return 1;
  err = intervals_aux(right,LE,&pos,&neg);
  if(err)
     return 1;
  if(f == LE)
     *next = pos;
  else if(equals(pos,trueterm))
     *next = falseterm;
  else if(equals(pos,falseterm))
     *next = trueterm;
  else  
     *next = reverse(pos);
  HIGHLIGHT(*next);
  strcpy(reason,english(487));  /* examine the signs         of the factors */
  return 0;
 }
/*_______________________________________________________________*/
static int dp_aux(term t, term *ans, unsigned short ineq)
/* if t is a product, delete all positive entire factors and
return the product of the remaining ones in *ans.  If
all the factors are positive, return *ans = one.  Return
zero if at least one factor was positive, 1 for wrong input
or failed to prove any factors positive.  Ineq is '<', '>', LE, or GE
or =  at the top-level call but can be '/' at a recursive call. */

{ unsigned short n = ARITY(t);
  unsigned short k;
  int i,err,err2,flag;
  term temp,num,denom;
  if(FUNCTOR(t) == '/')
     { err = dp_aux(ARG(0,t),&num,'/');
       err2 = dp_aux(ARG(1,t),&denom,'/');
       if(err)
          num = ARG(0,t);
       else
          HIGHLIGHT(num);
       if(err2)
          denom = ARG(1,t);
       else
          HIGHLIGHT(denom);
       if(err && err2)
          return 1;
       *ans = make_fraction(num,denom);
       return 0;
     }
  if(FUNCTOR(t) != '*')
      return 1;
  temp = make_term('*',n);
  k=0;
  for(i=0;i<n;i++)
     { if(!(entire(ARG(i,t)) && obviously_positive(ARG(i,t))))
          { ARGREP(temp,k,ARG(i,t));
            if(PROTECTED(ARG(i,t)))
               PROTECT(ARG(k,temp));
               /* factors (x-a+sqrt b) are left PROTECTED by surdsimp,
                  and must remain PROTECTED */
            ++k;
          }
       else
          flag = i;
     }
  if(k==0)
     { RELEASE(temp);
       return 1;
     }
  if(k==1)
     { *ans = ARG(0,temp);
       RELEASE(temp);
       return 0;
     }
  if(k == n-1 && INEQUALITY(ineq))
     { SetShowStepArg(ARG(flag,t));
       SetShowStepOperation(ineq == '=' ? diveqn : divineq);
     }
  if(k==n)
     { RELEASE(temp);
       errbuf(0,english(480));
       /* Can't identify any positive factor */
       return 1;
     }
  *ans = make_term('*',k);
  for(i=0;i<k;i++)
     ARGREP(*ans,i,ARG(i,temp));
  RELEASE(temp);
  return 0;
}
/*_______________________________________________________________*/
int droppositive1(term ineq, term arg, term *next, char *reason)
/* drop positive entire factors from < or > if one side is zero */
{ int err;
  unsigned short f = FUNCTOR(ineq);
  term left,right,temp;
  if(f != '<' && f != '>')
     return 1;
  left = f == '<' ? ARG(0,ineq) : ARG(1,ineq);
  right = f == '<' ? ARG(1,ineq) : ARG(0,ineq);
  if(ZERO(left))
     { err = dp_aux(right,&temp,'<');
       if(err)
          return 1;
       *next = f == '<' ? lessthan(zero,temp) : greaterthan(temp,zero);
       strcpy(reason, english(505));  /* drop positive factors */
       return 0;
     }
  else if(ZERO(right))
     { err = dp_aux(left,&temp, '<');
       if(err)
          return 1;
       *next = f == '<' ? lessthan(temp,zero) : greaterthan(zero,temp);
       strcpy(reason,english(505));
       return 0;
     }
  return 1;
}
/*_______________________________________________________________*/
int droppositive2(term ineq, term arg, term *next, char *reason)
/* drop positive factors from LE (or GE) if one side is zero */
{ int err;
  unsigned short f = FUNCTOR(ineq);
  term left,right,temp;
  if(f != LE && f != GE)
     return 1;
  left = f == LE ? ARG(0,ineq) : ARG(1,ineq);
  right = f == LE ? ARG(1,ineq) : ARG(0,ineq);
  if(ZERO(left))
     { err = dp_aux(right,&temp, LE);
       if(err)
          return 1;
       if(f == LE)
          *next = le(zero,temp);
       else
          *next = ge(temp,zero);
       strcpy(reason, english(505));  /* drop positive factors */
       return 0;
     }
  else if(ZERO(right))
     { err = dp_aux(left,&temp,LE);
       if(err)
          return 1;
       if(f == LE)
          *next = le(temp,zero);
       else
          *next = ge(temp,zero);
       strcpy(reason,english(505));
       return 0;
     }
  return 1;
}
#if 0  /* the following two operators are superfluous */
/*_______________________________________________________________*/
int posdenom1(term ineq, term arg, term *next, char *reason)
/* u/v > 0 => u > 0 if v > 0 */
{ term u,v;
  int err;
  unsigned short f = FUNCTOR(ineq);
  term left,right;
  if(f != '<' && f != '>')
     return 1;
  left = f == '<' ? ARG(0,ineq) : ARG(1,ineq);
  right = f == '<' ? ARG(1,ineq) : ARG(0,ineq);
  if(FUNCTOR(right) != '/')
     return 1;
  if(!ZERO(left))
     return 1;
  u = ARG(0,right);
  v = ARG(1,right);
  err = infer(positive(v));
  if(err)
     { errbuf(0,english(506));
        /* Can't verify denominator is positive */
       return 1;
     }
  HIGHLIGHT(u);
  *next = f == '<' ? lessthan(zero,u): greaterthan(u,zero);
  strcpy(reason,english(1622));  /* reason as given at top of function */
  return 0;
}
/*_______________________________________________________________*/
int posdenom2(term ineq, term arg, term *next, char *reason)
/* u/v \ge 0 => u \ge 0 if v > 0 */
{ term u,v;
  int err;
  if(FUNCTOR(ineq) != LE)
     return 1;
  if(FUNCTOR(ARG(1,ineq)) != '/')
     return 1;
  u = ARG(0,ARG(1,ineq));
  v = ARG(1,ARG(1,ineq));
  err = infer(positive(v));
  if(err)
     { errbuf(0,english(506));
        /* Can't verify denominator is positive */
       return 1;
     }
  HIGHLIGHT(u);
  *next = le(zero,u);
  strcpy(reason,english(1621)); /* u/v  \ge  0 => u \ge 0 if v>0 */
  return 0;
}
#endif

/*_______________________________________________________________*/
int posnum1(term ineq, term arg, term *next, char *reason)
/* u/v > 0 => v>0 if u>0   */
{ term u,v;
  int err;
  if(FUNCTOR(ineq) != '<')
     return 1;
  if(FUNCTOR(ARG(1,ineq)) != '/')
     return 1;
  u = ARG(0,ARG(1,ineq));
  v = ARG(1,ARG(1,ineq));
  err = infer(positive(u));
  if(err)
     { errbuf(0,english(507));
        /* Can't verify numerator is positive */
       return 1;
     }
  HIGHLIGHT(v);
  *next = lessthan(zero,v);
  strcpy(reason,english(1619));  /* u/v > 0 => v>0 if u>0 */
  return 0;
}
/*_______________________________________________________________*/
int posnum2(term ineq, term arg, term *next, char *reason)
/*  u/v  \ge  0 => v \ge 0 if u \ge 0 */
{ term u,v;
  int err;
  if(FUNCTOR(ineq) != LE)
     return 1;
  if(FUNCTOR(ARG(1,ineq)) != '/')
     return 1;
  u = ARG(0,ARG(1,ineq));
  v = ARG(1,ARG(1,ineq));
  err = infer(positive(u));
  if(err)
     { errbuf(0,english(507));
        /* Can't verify numerator is positive */
       return 1;
     }
  HIGHLIGHT(v);
  *next = le(zero,v);
  strcpy(reason, english(1620)); /* u/v  \ge  0 => v \ge 0 if u \ge 0 */
  return 0;
}
/*______________________________________________________________________*/
int explicitdomain(term t, term arg, term *next, char *reason)
/* use assumptions to reject wrong solutions introduced (for example) by squaring */
/* Example:  x/x > 0 simplifies to true, but the real solution
is x < 0 or x > 0; the assumption x != 0 was made when the domain
was analyzed.  So after we derive true, we must make this explicit
to get the right answer.

The plan is this:  Temporarily disable all assumptions.
Determine the domain of the current line,
and see if this proposition implies the current assumptions.
Whichever ones are not deducible must form the conjunctions of
a new proposition P.  The answer is and(currentline,P).  Note that
P might be a CNF in general; in a simpler case it might be
a disjunction like x < 1 or 2 < x,  while currentline is x < 7.
In that example *next = and(x<7, (x<1 or 2 <x)) = x<1 or 2<x<7.

Because this generates a mess if applied too soon, we only show it
in selectops, and it only succeeds, if the inequality t is already solved,
or if t is an OR term and all its args are solved inequalities.

*/
{ short savenextassumption = get_nextassumption();
  short marker;
  int i,err,retval;
  unsigned short count,k;
  unsigned short f;
  assumption **assumptions;
  term p,q,r,u;
  int *scratch;
  if(savenextassumption == 0)
     return 1;  /* nothing to make explicit */
  if(CHECKED(t))
     return 1;  /* this was output of a previous call; this is to
                   stop infinite regress when the inferences below
                   can't be carried out. */
  if(!solved(t,get_eigenvariable()))
     return 1;  /* It makes a mess if applied to general inequalities,
                   producing complicated Boolean combinations of inequalities */
  assumptions = get_assumptions();
  /* To temporarily disable the assumptions, we can't just
  set_nextassumption(0), because (1) we need to assume domain(t),
  and (2) the process of inference calls lpt, which calls polyval,
  which might make more assumptions.  Instead we set the PROVISIONAL
  bit in each current assumption.  Of course, some of them may
  already have it set, so we need to first make a record of this,
  so we can later restore the assumptions. */

  scratch = callocate(savenextassumption, sizeof(int));
  if(scratch == NULL)
     return 1;
  count = 0;
  for(i=0;i<savenextassumption;i++)
     { u = assumptions[i]->prop;
       if(equals(u,trueterm))
          continue;
       if(PROVISIONAL(u))
          scratch[i] = 1;
       else
          SETPROVISIONAL(assumptions[i]->prop);
       ++count;
     }
  p = domain(t);
  if(!equals(p,trueterm))
     assume(p);  /* temporarily */
  f = FUNCTOR(t);
  marker = get_nextassumption();
  if(INEQUALITY(f))
     assume(t);
  else if(f == AND)
     { for(i=0;i<ARITY(t);i++)
          assume(ARG(i,t));
     }
  q = make_term(AND,count);
  k=0;
  for(i=0;i<savenextassumption;i++)
     { if(equals(assumptions[i]->prop,trueterm))
          continue;
       copy(assumptions[i]->prop,&u);
       clear_already(&u);  /* otherwise lpt won't touch it, and the
                              new assumptions won't be used.  E.g.
                              the new assumption 0 < x won't be used
                              to simplify x!=0 to true */
       err = infer(u);
       if(err)
          { ARGREP(q,k,u);
            HIGHLIGHT(ARG(k,q));
            ++k;
          }
     }
  if(k==0)
     retval = 1;  /* nothing to add, but don't return
                     till we have restored assumptions */
  else if(k==1)
    { u = ARG(0,q);
      RELEASE(q);
      q = u;
      retval = 0;
    }
  else
     { SETFUNCTOR(q,AND,k);
       retval = 0;
     }
  if(retval == 0)
     { if(equals(t,trueterm))
          { r = eliminate_ne(q);
            *next = lpt(r);
          }
       else
          { set_nextassumption(marker); /*  without limiting the use of assumptions,
                                           the next line will reduce t to true. */
            *next = lpt(and(t,q));  /* for example, if q is x != 0 and t is x <= 0 we get x < 0 */
            if((f == '>' || f == GE) &&
               econstant(ARG(0,*next)) &&
               !constant(ARG(1,*next)) &&
               (FUNCTOR(*next) == '<' || FUNCTOR(*next) == LE)
              )
                { *next = FUNCTOR(*next) == '<' ?
                            greaterthan(ARG(1,*next),ARG(0,*next)) :
                            ge(ARG(1,*next),ARG(0,*next));
                }
            if(contains(*next,NE))
                { r = eliminate_ne(*next);
                  *next = lpt(r);
                }
          }
     }
  set_nextassumption(savenextassumption);
  /* Now restore the assumptions to their original condition */
  for(i=0;i<savenextassumption;i++)
     { if(!scratch[i])
          UNSETPROVISIONAL(assumptions[i]->prop);
     }
  free2(scratch);
  if(retval)
     return 1;
  HIGHLIGHT(*next);
  /* Below we use SETCHECKED to prevent a subsequent call to explicitdomain
     on the same inequalities from doing anything further, and hence stop
     various ugly infinite regresses.
  */
  if(FUNCTOR(*next) == OR)
     { for(i=0;i<ARITY(*next);i++)
          { HIGHLIGHT(ARG(i,*next));
            f = FUNCTOR(ARG(i,*next));
            if(INEQUALITY(f) || f == AND || f == OR)
                SETCHECKED(ARG(i,*next));
          }
     }
  f = FUNCTOR(*next);
  if(INEQUALITY(f) || f == AND)
     SETCHECKED(*next);
  if(f == AND)
     { for(i=0;i<ARITY(*next);i++)
          SETCHECKED(ARG(i,*next));
     }
  strcpy(reason, english(1574));  /* use assumptions */
  return 0;
}

/*_________________________________________________________________________*/
static term eliminate_ne(term t)
/* replace NE(a,b) by or(a<b,b<a) throughout t */
{ unsigned short n,f;
  int i;
  term u,v;
  if(ATOMIC(t))
     return t;
  f = FUNCTOR(t);
  n = ARITY(t);
  if(f == NE)
     { copy(ARG(0,t),&u);
       copy(ARG(1,t),&v);
       return or(lessthan(ARG(0,t),ARG(1,t)),lessthan(v,u));
       /* copy to avoid creating a DAG */
     }
  u = make_term(f,n);
  for(i=0;i<n;i++)
     ARGREP(u,i,eliminate_ne(ARG(i,t)));
  return u;
}

/*___________________________________________________________*/
static term reverse(term t)
/* if t is a < b return b > a, etc. for other inequalities,
and if t is an OR of inequalities, reverse them all. */
{ unsigned short n;
  unsigned short f = FUNCTOR(t);
  int i;
  term ans;
  if(f == OR)
     { n = ARITY(t);
       ans = make_term(OR,n);
       for(i=0;i<n;i++)
          ARGREP(ans,i,reverse(ARG(i,t)));
       return ans;
     }
  switch(f)
     { case '<' :
          return greaterthan(ARG(1,t),ARG(0,t));
       case '>' :
          return lessthan(ARG(1,t),ARG(0,t));
       case LE  :
          return ge(ARG(1,t),ARG(0,t));
       case GE  :
          return le(ARG(1,t),ARG(0,t));
     }
  return t;  /*  = or NE maybe */
}


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