Sindbad~EG File Manager

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

/* invert_ineq,  which solves some inequalities in which the unknown occurs
only once.  Domain needs this for interval_form, used in calculating
domains of definite integrals. */
/* M. Beeson
6.9.92 file created
1.29.98 last modified
*/

#include <assert.h>
#include <math.h>
#include "globals.h"
#include "prover.h"
#include "eqn.h"
#include "algaux.h"
#include "invineq.h"
#include "pvalaux.h"  /* twoparts */
/*_________________________________________________________________*/
int invert_ineq(term u,term c,term x,term *ans,unsigned short *g)

 /* solves some one-to-one inequalities (u<c or u<=c) assuming complex is off;
including linear equations, equations involving SQRT and ROOT and
trig and argtrig functions.  The unknown x must occur only once and only
on the left side, i.e. in u.  The variable g is used to pass IN the
inequality sign between u and c (which can be <, >, LE, or GE, but not NE)
and again to pass OUT the sign of the solved inequality x *g *ans.

returns 0 if x *g *ans solves u *g c for x;
returns -1 if equation is impossible, e.g.  sin x = 2;
returns 1 if it can't figure it out, or an error condition arises,
such as a non-one-to-one function.
   Example:   if u is  tan x;   then *ans = arctan c
This function just applies inverse functions WITHOUT checking that
the resulting terms are defined.  The calling function should then
check that *ans is defined.
*/
{ term a,v,denom,num,temp,power;
  unsigned short f;
  int err,sign;
  unsigned short originalg = *g;  /* restore it before failing */
  start:   /* label used for tail recursion */
  sign = 0;
  if(contains(c,FUNCTOR(x)))  /* x must appear only on the left */
     { *g = originalg;
       return 1;
     }
  if(equals(u,x))  /* already solved */
     { *ans = c;
       return 0;
     }
  if(ATOMIC(u))
     { *g = originalg;
       return 1;   /* should never get such a call */
     }
  f = FUNCTOR(u);
  v = ARG(0,u);
  if(f=='/' && ZERO(c))  /*  a/b < 0  iff ab < 0  etc */
     { denom = ARG(1,u);
       polyval(signedproduct(v,denom),&temp);
       err = invert_ineq(temp,zero,x,ans,g);
       if(err)
          return err;
       if(*g == LE || *g == GE)
            /* careful:  1/x \le 0 isn't equivalent to x\le 0,
            and  a/b \le 0 isn't equivalent to a/b < 0 either */
          { err = infer(ne(zero,v));
            if(!err)
               { *g = SWITCH(*g);
                 return 0;
               }
            err = infer(ne(zero,denom));
            if(!err)
               return 0;   /* without changing *g */
            *g = originalg;
            return 1;   /* if can't determine that either num or denom is
                            nonzero, it's too hard. */
          }
     }
  if(f=='/' && !contains(ARG(1,u),FUNCTOR(x)))
     { denom = ARG(1,u);
       err = infer(lessthan(zero, denom));
       if(err)
          { err = infer(lessthan(denom,zero));
            if(err)
               { *g = originalg;
                 return 1;  /* can't determine sign of denom */
               }
            *g = SWITCH(*g);
          }
       polyval(signedproduct(denom,c),&temp);
       u = v;
       c = temp;
       goto start;
     }
  if(f=='/' && !contains(v,FUNCTOR(x)))
     { denom = ARG(1,u);
       err = infer(lessthan(zero, denom));
       if(err)
          { err = infer(lessthan(denom,zero));
            if(err)
                { *g = originalg;
                  return 1;  /* can't determine sign of denom */
                }
            *g = SWITCH(*g);
          }
       polyval(signedfraction(v,c),&temp);
       u = denom;
       c = temp;
       goto start;
     }
  if(f=='*')
     { twoparts(u,x,&a,&v);
       if(ONE(a))
          return 1;   /* u is a product of two or more terms containing x */
       if((OBJECT(a) || RATIONALP(a)) && !ISZERO(a))
          /* don't call infer in this simple case */
          err = 0;
       else
          err = infer(lessthan(zero, a));
       if(err)
          { err = infer(lessthan(a,zero));
            if(err)
               return 1;  /* can't determine sign of denom */
            *g = SWITCH(*g);
          }
       polyval(signedfraction(c,a),&temp);
       u = v;
       c = temp;
       goto start;
     }
  if(f=='+')
     { unsigned short i, n = ARITY(u);
       int count=0,marker = 0;  // marker is initialized just to silence a warning
       term s;
       if(n==2)  /* common case */
          { for(i=0;i<2;i++)
              { if(!contains(ARG(i,u),FUNCTOR(x)))
                    { polyval(sum(c,tnegate(ARG(i,u))),&temp);
                      return invert_ineq(ARG(i ? 0 : 1,u),temp,x,ans,g);
                    }
              }
            return 1;
          }
       assert(n > 2);
       for(i=0;i<n;i++)
          { s = ARG(i,u);
            if(contains(s,FUNCTOR(x)))
                { if(count)
                     { *g = originalg;
                       return 1;  /* more than one term with x in it */
                     }
                  else
                    { ++count;
                      marker = i;
                    }
                }
          }
       if(!count)
          { *g = originalg;
            return 1;
          }
       temp = make_term('+',(unsigned short)(n-1));
       /* put all the terms except the one with index marker in temp */
       for(i=0;i<n;i++)
          { if(i<marker)
               ARGREP(temp,i,ARG(i,u));
            else if (i> marker)
               ARGREP(temp,i-1,ARG(i,u));
          }
       polyval(sum(c,tnegate(temp)),&a);
       u = ARG(marker,u);
       c = a;
       goto start;
     }
  if(f=='^' && !contains(v,FUNCTOR(x)))
     { if(equals(v,eulere))
          return invert_ineq(ARG(1,u),ln1(c),x,ans,g);
       err = infer(lessthan(zero,v));
       if(err)
          { *g = originalg;
            return 1;  /* negative base too hard */
          }
       u = ARG(1,u);
       c = make_fraction(ln1(c),ln1(v));
       goto start;
     }
  if(f=='^' && INTEGERP(ARG(1,u)) && ISODD(ARG(1,u)) && !contains(c,FUNCTOR(x)))
         /* x^3 = -1 for example */
     { if(NEGATIVE(c))
         { c = ARG(0,c);
           sign = -1;
         }
       else
          sign = 1;
       if(FUNCTOR(c) == '^')
          { polyval(product(ARG(1,c),reciprocal(ARG(1,u))),&temp);
            temp = make_power(ARG(0,c),temp);
          }
       else
          temp = make_power(c,reciprocal(ARG(1,u)));
       u = v;
       c = sign == -1 ? tnegate(temp) : temp;
       goto start;
     }
  if(f=='^' && !contains(ARG(1,u),FUNCTOR(x)))
     { /* lambda(x,x^n) is one-one only if n is an odd integer,
          or a rational with an odd denom and odd num */
       power = ARG(1,u);
       err = infer(le(zero,v));
       if(!err)  /* then need not worry about whether power is odd or not */
          { /* but we still need to know if power >0  or < 0 */
            err = infer(lessthan(zero,power));
            if(err)
               { err = infer(lessthan(power,zero));
                 if(err)
                    return 1;
                 *g = SWITCH(*g);
               }
            if(!infer(le(zero,c)) || !infer(odd(power)))
               { polyval(make_power(c,reciprocal(power)),&temp);
                 u = v;
                 c = temp;
                 goto start;
               }
            /* c < 0 and power is even */
            *g = originalg;
            return 1;
          }
       if(FRACTION(power))
          { num = ARG(0,power);
            denom = ARG(1,power);
            if(!INTEGERP(num))
              { err = infer(type(num,INTEGER));
                if(err)
                   { *g = originalg;
                     return 1;
                   }
              }
            if(!INTEGERP(denom))
               { err = infer(type(denom,INTEGER));
                 if(err)
                    { *g = originalg;
                      return 1;
                    }
               }
            err = infer(odd(denom));
            if(err)
               { *g = originalg;
                 return 1;
               }
            err = infer(odd(num));
            if(err)
               { *g = originalg;
                 return 1;
               }
          }
       else if(!INTEGERP(power))
          { err = infer(type(power,INTEGER));
            if(err)
               { *g = originalg;
                 return 1;
               }
            err = infer(odd(power));
            if(err)
               { *g = originalg;
                 return 1;
               }
          }
       err = infer(even(power));
       if(!err)
         /* function isn't one-one, so can't invert unless v has one sign */
          { err= infer(le(zero,v)); /* then it would still be ok */
            if(err)
               { err = infer(le(v,zero));
                 if(err)
                    { *g = originalg;
                      return 1;
                    }
                 else
                    sign = -1;
               }
            else
               sign = 1;
          }
       else
          { err = infer(odd(power));
            if(err)
               { *g = originalg;
                 return 1; /* can't tell if power is even or odd */
               }
          }
       if(!infer(le(zero,c)) || !infer(odd(power)))
          { polyval(make_power(c,reciprocal(power)),&temp);
            if(sign == -1)
               { *g = SWITCH(*g);
                 temp = tnegate(temp);
               }
            u = v;
            c = temp;
            goto start;
          }
       *g = originalg;
       return 1;
     }
  if(f==ROOT)
     { if(contains(v,FUNCTOR(x)))
          return 1;
       u = ARG(1,u);
       c = make_power(c,ARG(0,u));
       goto start;
     }
  if(ARITY(u) != 1)
     return 1;
  if(f == FUNCTOR(c))
     { u = v;
       c = ARG(0,c);
       goto start;
     }
  u = v;
  switch(f)
     { case '-' :
          c = tnegate(c);
          if(*g != '=' && *g != NE)
             *g = SWITCH(*g);
          break;
       case TAN :
          c = atan1(c);
          break;
       case SQRT:
          c = make_power(c,two);
          break;
       case LN  :
          c = make_power(eulere,c);
          break;
       case SINH:
          c = asinh1(c);
          break;
       case ASINH:
          c = sinh1(c);
          break;
       case ATAN :
          c = tan1(c);
          break;
       case COT :
          c = atan1(reciprocal(c));
          break;
       case ACOT :
          c = cot1(c);
          break;
       case TANH:
          c = atanh1(c);
          break;
       case ATANH:
          c = tanh1(c);
          break;
       default:
          return 1;   /* nothing more to try */
    }
  goto start;         /* tail recursion */
}

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