Sindbad~EG File Manager

Current Path : /home/beeson/Otter-Lambda/yyy/algebra/
Upload File :
Current File : //home/beeson/Otter-Lambda/yyy/algebra/absolute.c

/* operators for MathXpert's absolute value menu
M. Beeson
original date 12.14.90
3.1.98 last modified
3.28.00 corrected divabs2 at line 850,  ARG(i,t) changed to ARG(i,num)
4.2.00 added  intervaltoabs1, intervaltoabs2, absevepowerrev, and abspowerrev
3.17.06  changed 'LE' to LE.  This must have happened when eliminating the OEM character for LE.
*/

#define ALGEBRA_DLL
#include <string.h>
#include <assert.h>
#include <math.h>
#include "globals.h"
#include "ops.h"
#include "prover.h"  /* lpt     */
#include "eqn.h"     /* ssolve  */
#include "getprob.h" /* show_ringflag etc. */
#include "deval.h"   /* nearint */
#include "cancel.h"  /* cancel  */
#include "pvalaux.h" /* topflatten, iseven */
#include "symbols.h"
#include "sqrtfrac.h" /* cancel_abs */
#include "errbuf.h"
#include "order.h"   /* iscomplex */
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int abspos(term t, term arg, term *next, char *reason)
/*  |a|=a if a�0 */

/*  This is called when integrating |f(x)|.  Therefore it must be
able to work when professors can easily infer that f(x) is nonnegative
(on the interval of integration).  But the prover doesn't reduce all
inequalities to solved form, because that introduces ugly Boolean
combinations.  Hence the direct call to ssolve in this operator and
in absneg.  */

{ int err;
  short savenextassumption;
  int savenvariables;
  int savenextdefn;
  term u,ineq,x;
  if(FUNCTOR(t) != ABS)
     return 1;
  if(PRIME(t))
     return 1;
  /* PRIME on an ABS term means no use trying to determine the sign */
  x = get_eigenvariable();
  savenextdefn = get_nextdefn();
  savenextassumption = get_nextassumption();
  savenvariables = get_nvariables();
  u = ARG(0,t);
  ineq = le(zero,u);
  err = infer(ineq);
  if(!err)
     { *next = u;
       HIGHLIGHT(*next);
       strcpy(reason, english(288));  /*  |a|=a if a�0 */
       return 0;
     }
  /* Now fail */
  set_nextassumption(savenextassumption);
  set_nvariables(savenvariables);
  set_nextdefn(savenextdefn);
  errbuf(0,""); /* erase any misleading messages left by ssolve */
  return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absposandassume(term t, term arg, term *next, char *reason)
/*  |a|=a and assume a � 0 if it can't be inferred */

{ int err;
  if(FUNCTOR(t) != ABS)
     return 1;
  err= abspos(t,arg,next,reason);
  if(!err)
     return 0;
  if(!PRIME(t))
     { err = infer(lessthan(ARG(0,t),zero));
       if(!err)
          return 1;
     }
  assume(le(zero,ARG(0,t)));
  *next = ARG(0,t);
  HIGHLIGHT(*next);
  strcpy(reason, english(288));  /*  |a|=a if a�0 */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absneg(term t, term arg, term *next, char *reason)
/*  |a|= -a if a�0 */
/*  See additional comments under abspos */

{ int err;
  short savenextassumption;
  int savenextdefn;
  int savenvariables;
  term u,ineq,x;
  if(FUNCTOR(t) != ABS)
     return 1;
  if(PRIME(t))
     return 1;
  x = get_eigenvariable();
  savenvariables = get_nvariables();
  savenextdefn = get_nextdefn();
  savenextassumption = get_nextassumption();
  u = ARG(0,t);
  ineq = le(u,zero);
  err = infer(ineq);
  if(!err)
     { *next = tnegate(u);
       HIGHLIGHT(*next);
       strcpy(reason, english(289));  /*  |a|= -a if a�0 */
       return 0;
     }
  /* Now fail */
  set_nextassumption(savenextassumption);
  set_nvariables(savenvariables);
  set_nextdefn(savenextdefn);
  errbuf(0,""); /* erase any misleading messages left by ssolve */
  return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absdef(term t, term arg, term *next, char *reason)
/* |u|=u if u�0; -u if u�0 */
{ int err;
  term u,arg0,arg1;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) != ABS)
     return 1;
  if(PRIME(t))
     return 1;
  u = ARG(0,t);
  err = infer(le(zero,u));
  if(!err)
     { *next = u;
       strcpy(reason, english(290));   /*  |u|=u if u�0 */
       HIGHLIGHT(*next);
       return 0;
     }
  err = infer(le(u,zero));
  if(!err)
     { *next = tnegate(u);
       strcpy(reason,english(291));    /* |u|=-u if u�0 */
       HIGHLIGHT(*next);
       return 0;
     }
  /* if can't infer either one use a CASES term */
  *next = make_term(CASES,2);
  arg0 = make_term(IF,2);
  arg1 = make_term(IF,2);
  ARGREP(arg0,0,le(zero,u));
  ARGREP(arg1,0,le(u,zero));
  ARGREP(arg0,1,u);
  ARGREP(arg1,1,tnegate(u));
  ARGREP(*next,0,arg0);
  ARGREP(*next,1,arg1);
  strcpy(reason, english(292));   /* definition of |u| */
  HIGHLIGHT(*next);
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int abslessthan(term t, term arg, term *next, char *reason)
 /* |u|<v iff -v < u < v */

{ term left,u,v;
  int err;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) == LE)
     errbuf(0, english(293)); /* Maybe you meant � instead of <" */
  if(FUNCTOR(t) != '<')
     return 1;
  left = ARG(0,t);
  if(ATOMIC(left))
     return 1;
  if(FUNCTOR(left) != ABS)
     return 1;
  u = ARG(0,left);
  v = ARG(1,t);
  if(constant(v))
     err = check(le(zero,v));
  else
     err = infer(le(zero,v));
  if(err)
     { errbuf(0, english(1549));  /* Right side must be non-negative */
       return 1;
     }
  *next = and(lessthan(tnegate(v),u), lessthan(u,v));
  HIGHLIGHT(*next);
  strcpy(reason, english(294));  /* |u|<v iff -v < u < v */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absgreaterthan(term t, term arg, term *next, char *reason)
 /* v > |u| iff -v < u < v */

{ term right,u,v;
  int err;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) != '>')
     return 1;
  right = ARG(1,t);
  if(ATOMIC(right))
     return 1;
  if(FUNCTOR(right) != ABS)
     return 1;
  u = ARG(0,right);
  v = ARG(0,t);
  if(constant(v))
     err = check(le(zero,v));
  else
     err = infer(le(zero,v));
  if(err)
     { errbuf(0, english(1598));  /* Left side must be non-negative */
       return 1;
     }
  *next = and(lessthan(tnegate(v),u), lessthan(u,v));
  HIGHLIGHT(*next);
  strcpy(reason, english(1599)); /* v>|u| iff -v < u < v */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absle(term t, term arg, term *next, char *reason)
 /* |u|�v iff -v � u � v */
{ term left,u,v;
  int err;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) == '<')
     errbuf(0, english(295));
     /* Maybe you meant < instead of � */
  if(FUNCTOR(t) != LE)
     return 1;
  left = ARG(0,t);
  if(ATOMIC(left))
     return 1;
  if(FUNCTOR(left) != ABS)
     return 1;
  u = ARG(0,left);
  v = ARG(1,t);
  if(constant(v))
     err = check(le(zero,v));
  else
     err = infer(le(zero,v));
  if(err)
     { errbuf(0, english(1549));  /* Right side must be non-negative */
       return 1;
     }
  *next = and(le(tnegate(v),u), le(u,v));
  HIGHLIGHT(*next);
  strcpy(reason, english(296));  /* |u|�v iff -v � u � v */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absge(term t, term arg, term *next, char *reason)
 /* v�|u| iff -v � u � v */
{ term right,u,v;
  int err;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) != GE)
     return 1;
  right = ARG(1,t);
  if(ATOMIC(right))
     return 1;
  if(FUNCTOR(right) != ABS)
     return 1;
  u = ARG(0,right);
  v = ARG(0,t);
  if(constant(v))
     err = check(le(zero,v));
  else
     err = infer(le(zero,v));
  if(err)
     { errbuf(0, english(1598));  /*  Left side must be non-negative */
       return 1;
     }
  *next = and(le(tnegate(v),u), le(u,v));
  HIGHLIGHT(*next);
  strcpy(reason, english(1600)); /* v�|u| iff -v � u � v */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int lessthanabs(term t, term arg, term *next, char *reason)
/* u<|v| iff u<-v or u<v */

{ term right,u,v;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) == LE)
     errbuf(0, english(293));
     /* Maybe you meant � instead of < */
  if(FUNCTOR(t) != '<')
     return 1;
  right = ARG(1,t);
  if(ATOMIC(right))
     return 1;
  if(FUNCTOR(right) != ABS)
     return 1;
  v = ARG(0,right);
  u = ARG(0,t);
  *next = or(lessthan(v,tnegate(u)), lessthan(u,v));
  HIGHLIGHT(*next);
  strcpy(reason, english(297)); /* u<|v| iff v<-u or u<v */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int greaterthanabs(term t, term arg, term *next, char *reason)
/* |v|>u iff v < -u or v > u */

{ term left,u,v;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) != '>')
     return 1;
  left = ARG(0,t);
  if(ATOMIC(left))
     return 1;
  if(FUNCTOR(left) != ABS)
     return 1;
  v = ARG(0,left);
  u = ARG(1,t);
  *next = or(lessthan(v,tnegate(u)), greaterthan(v,u));
  HIGHLIGHT(*next);
  strcpy(reason, english(1601)); /* |v|>u iff v<-u or v>u */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int leabs(term t, term arg, term *next, char *reason)
 /* u�|v| if v�-u or u�v */
{ term right,u,v;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) == '<')
     errbuf(0,english(295));
     /* Maybe you meant < instead of � */
  if(FUNCTOR(t) != LE)
     return 1;
  right = ARG(1,t);
  if(ATOMIC(right))
     return 1;
  if(FUNCTOR(right) != ABS)
     return 1;
  v = ARG(0,right);
  u = ARG(0,t);
  *next = or(le(v,tnegate(u)), le(u,v));
  HIGHLIGHT(*next);
  strcpy(reason, english(298));  /* u�|v| iff v�-u or u�v */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int geabs(term t, term arg, term *next, char *reason)
 /*|v|�u if v � -u or v � u */
{ term left,u,v;
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) != GE)
     return 1;
  left = ARG(0,t);
  if(ATOMIC(left))
     return 1;
  if(FUNCTOR(left) != ABS)
     return 1;
  v = ARG(0,left);
  u = ARG(1,t);
  *next = or(le(v,tnegate(u)), ge(v,u));
  HIGHLIGHT(*next);
  strcpy(reason, english(1602));  /* |v|�u if v�-u or v�u */
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int absevenpower(term in, term arg, term *next, char *reason)
   /* |u|^2�=u^2� (u real) */
{ term t,u,n;
  int err;
  if(FUNCTOR(in) != '^')
     return 1;
  t = ARG(0,in);
  if(FUNCTOR(t) != ABS)
     return 1;
  u = ARG(0,t);
  n = ARG(1,in);
  if(!iseven(n))
     return 1;
  if(get_complex())
     { err = infer(type(u,R));
       if(err)
          { errbuf(0, english(299));
            /* |u|^2�=u^2� requires u to be real */
            return 1;
          }
     }
  /* complex_visible = 1;  cause "Using real numbers only" to get displayed */
  *next = make_power(u,n);
  HIGHLIGHT(*next);
  strcpy(reason, english(300));  /* |u|^2� = u^2�  */
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int abspower(term in, term arg, term *next, char *reason)
   /*  |u�|=|u|� if n is real */
   /*  and if(! complex) then check(u�0) */
{ term t,u,n;
  int err;
  if(FUNCTOR(in) != ABS)
     return 1;
  t = ARG(0,in);
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  n = ARG(1,t);
  err = infer(type(n,R));
  if(err)
     return 1;

  /* There are difficulties:  how about if n = 1/2 and
     u = -2;  so we are talking about |�(-2)| which is undefined if
     we don't allow complex numbers, while on the right we have �2 which
     is defined in any case.  */

  *next = make_power(absolute(u),n);
  HIGHLIGHT(*next);
  strcpy(reason, english(301));   /*  |u�|=|u|� (u real) */
  if(get_complex())
     return 0;   /* no problem */
    /* but if !complex, the left side has to be defined */
  err = check(domain(t));
  if(err)
     { errbuf(0, english(302));
          /* Undefined power.  You have complex numbers off. */
          /* You could only get here if such an undefined expression
             arises inside a limit term.  */
       return 1;
     }
  return 0;
}

/*___________________________________________________________________*/
/* multiplyabsval  is in radsimp.c */
/* absofproduct is in sqrtfrac.c   */
/*___________________________________________________________________*/

MEXPORT_ALGEBRA int abslinear(term t, term arg, term *next, char *reason)
 /*   |cu| = c|u| if c � 0  */
{ term u,c,w;
  unsigned short n,j,k;
  int i,err;
  if(FUNCTOR(t) != ABS || FUNCTOR(ARG(0,t)) != '*')
     return 1;
  strcpy(reason, english(305));  /* |cu| = c|u| if c � 0 */
  w = ARG(0,t);
  n = ARITY(w);
  c = make_term('*',n);
  u = make_term('*',n);
  j=k=0;
  for(i=0;i<n;i++)  /* throw positive factors in c, others in u */
    { err = infer(le(zero,ARG(i,w)));
      if(!err)
         { ARGREP(c,j,ARG(i,w));
           ++j;
         }
      else
         { ARGREP(u,k,ARG(i,w));
           ++k;
         }
    }
  if(j==0)
     return 1;
  if(k==0)
     { *next = c;
       HIGHLIGHT(*next);
       strcpy(reason, english(306));  /* |u| = c if c�0 */
       RELEASE(u);
       return 0;
     }
   if(j==1 && k==1)  /* and n == 2 */
     { *next = product(ARG(0,c),abs1(ARG(0,u)));
       RELEASE(c);
       RELEASE(u);
     }
   else if(j==1)
     { SETFUNCTOR(u,'*',k);
       *next = product(ARG(0,c),abs1(u));
       RELEASE(c);
     }
   else if(k==1)
     { SETFUNCTOR(c,'*',j);
       *next = product(c,abs1(ARG(0,u)));
       RELEASE(u);
     }
   else
     { SETFUNCTOR(c,'*',j);
       SETFUNCTOR(u,'*',k);
       *next = product(c,abs1(u));
     }
   HIGHLIGHT(*next);
   return 0;
}
/*___________________________________________________________________*/
MEXPORT_ALGEBRA int absineqtrue(term t, term arg, term *next, char *reason)
/* |u| � 0  is always true */
{ if(FUNCTOR(t) != LE && FUNCTOR(t) != GE)
     return 1;
  if(FUNCTOR(t) == LE)
     { if(FUNCTOR(ARG(1,t)) != ABS)
          return 1;
       if(! ZERO(ARG(0,t)))
          return 1;
       strcpy(reason, english(307));  /* 0 � |u| is true */
     }
  else /* GE */
     { if(FUNCTOR(ARG(0,t)) != ABS)
          return 1;
       if( ! ZERO(ARG(1,t)))
          return 1;
       strcpy(reason, english(308));  /* |u| � 0 is true */
     }
  *next = true;
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_ALGEBRA int absineqfalse(term t, term arg, term *next, char *reason)
/* |u| < 0  is always false */
{ if(FUNCTOR(t) != '<' && FUNCTOR(t) != '>')
     return 1;
  if(FUNCTOR(t) == '<')
     { if(FUNCTOR(ARG(0,t)) != ABS)
          return 1;
       if(! ZERO(ARG(1,t)))
          return 1;
       strcpy(reason, english(309));   /* |u| < 0 is false */
     }
  else /* > */
     { if(FUNCTOR(ARG(1,t)) != ABS)
          return 1;
       if( ! ZERO(ARG(0,t)))
          return 1;
       strcpy(reason, english(310));   /*  0 > |u| is false */
     }
  *next = false;
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_ALGEBRA int abseqn2(term t, term arg, term *next, char *reason)
/*   |u|/u = c => c = �1 */
/*  reject |u|/u=c unless c=�1, by returning 'false'  */
/*  also works on u/|u| = c */
{ int err;
  term a,b,c,u;
  const char *reason1 = english(311);  /* |u|/u=1 iff 0 < u */
  const char *reason2 = english(312);  /* u/|u|=1 iff 0 < u */
  const char *reason3 = english(313);  /* |u|/u=-1 iff u<0  */
  const char *reason4 = english(314);  /* u/|u|=-1 iff u<0  */
  const char *reason5 = english(315);  /* |u|/u=c => c=�1   */
  long kk;
  double cval;
  if(FUNCTOR(t) != '=')
     return 1;
  if(FUNCTOR(ARG(0,t)) != '/')
     return 1;
  a = ARG(0,ARG(0,t));
  b = ARG(1,ARG(0,t));
  c = ARG(1,t);
  if( FUNCTOR(a) == ABS && equals(ARG(0,a),b))
      u = b;
  else if (FUNCTOR(b)==ABS && equals(ARG(0,b),a))
      u = a;
  else return 1;
  if(seminumerical(c))
    { err = deval(c,&cval);
      if(err)
         goto reject;
      if(nearint(cval,&kk) && labs(kk)==1 )
         { out:
           if(kk > 0)
              { *next = lessthan(zero,u);
                strcpy(reason,FUNCTOR(a)==ABS ? reason1 : reason2);
                return 0;
              }
           else
              { *next = lessthan(u,zero);
                strcpy(reason,FUNCTOR(a)==ABS ? reason3 : reason4);
                return 0;
              }
         }
      else
         { reject:
           *next = false;
           strcpy(reason,reason5);
           return 0;
         }
    }
  err = infer(equation(c,one));
  if(!err)
     { kk = 1;
       goto out;
     }
  err = infer(equation(c,minusone));
  if(!err)
     { kk = -1;
       goto out;
     }
  err = refute(equation(c,one));
  if(!err)
     { *next = le(u,zero);
       strcpy(reason,reason5);
       HIGHLIGHT(*next);
       return 0;
     }
  err = refute(equation(c,minusone));
  if(!err)
     { *next = le(zero,u);
       strcpy(reason,reason5);
       HIGHLIGHT(*next);
       return 0;
     }
  *next = or(equation(c,one),equation(c,minusone));
  set_checksolutionsflag(1);
     /*  Really it should be or(and(equation(c,okne),lessthan(u,zero))
                                and(equation(c,minusone),lessthan(zero,u))
                               )
         but MathXpert can't cope with and inside or, so instead we
         just generate spurious solutions and check them in the end.
         Consider two examples:  |x|/x = x and |x|/x = -x */
  strcpy(reason,reason5);
  HIGHLIGHT(*next);
  return 0;
}
/*______________________________________________________________*/
MEXPORT_ALGEBRA int fractionofabs(term t, term arg, term *next, char *reason)
/*  |a|/|b| = |a/b|  */
{ term a,b;
  if(! FRACTION(t) || FUNCTOR(ARG(0,t)) != ABS || FUNCTOR(ARG(1,t)) != ABS)
     return 1;
  a = ARG(0,ARG(0,t));
  b = ARG(0,ARG(1,t));
  *next = abs1(make_fraction(a,b));
  HIGHLIGHT(*next);
  strcpy(reason, english(1131)); /* |a|/|b| = |a/b| */
  return 0;
}

/*______________________________________________________________*/
MEXPORT_ALGEBRA int absoffraction(term t, term arg, term *next, char *reason)
/*   |a/b| = |a|/|b| */
{ term a,b,absa,absb;
  if(FUNCTOR(t) != ABS || !FRACTION(ARG(0,t)))
     return 1;
  a = ARG(0,ARG(0,t));
  b = ARG(1,ARG(0,t));
  absa = abs1(a);
  absb = abs1(b);
  if(PRIME(t))
     { void  *savenode = heapmax();
       int err = infer(le(zero,a));
       if(err)
          { reset_heap(savenode);
            err = infer(le(a,zero));
            if(err)
               { /* can't determine the sign of a */
                 SETPRIME(absa);
                 SETPRIME(absb);  /* since t was PRIME */
                 /* Saves further repeated attempts to apply absneg, abspos */
               }
          }
       reset_heap(savenode);
     }
  *next = make_fraction(absa,absb);
  HIGHLIGHT(*next);
  strcpy(reason,english(1132));    /*   |a/b| = |a|/|b| */
  return 0;
}

/*______________________________________________________________*/
MEXPORT_ALGEBRA int abslinearquo(term t, term arg, term *next, char *reason)
/*   |a/b| = |a|/b if b > 0 */
{ term a,b;
  if(FUNCTOR(t) != ABS || !FRACTION(ARG(0,t)))
     return 1;
  a = ARG(0,ARG(0,t));
  b = ARG(1,ARG(0,t));
  if(!OBJECT(b))
     return 1;
  *next = make_fraction(abs1(a),b);
  if(PRIME(t))
     SETPRIME(*next);
  HIGHLIGHT(*next);
  strcpy(reason,english(1133)); /* |a/b| = |a|/b if b>0 */
  return 0;
}
/*______________________________________________________________*/
MEXPORT_ALGEBRA int abssqrt(term t, term arg, term *next, char *reason)
/* |�a| = �|a| */
{ term a;
  if(FUNCTOR(t) != ABS || !FUNCTOR(ARG(0,t))==SQRT)
     return 1;
  a = ARG(0,ARG(0,t));
  *next = make_sqrt(abs1(a));
  if(PRIME(t))
     SETPRIME(ARG(0,*next));
  HIGHLIGHT(*next);
  strcpy(reason,"$|�a| = �|a|$");
  return 0;
}

/*______________________________________________________________*/
MEXPORT_ALGEBRA int absroot(term t, term arg, term *next, char *reason)
/* |��a| = ��|a| */
{ term a,n;
  if(FUNCTOR(t) != ABS || FUNCTOR(ARG(0,t)) != ROOT)
     return 1;
  n = ARG(0,ARG(0,t));
  a = ARG(1,ARG(0,t));
  *next = make_root(n,abs1(a));
  if(PRIME(t))
     SETPRIME(ARG(1,*next));
  HIGHLIGHT(*next);
  strcpy(reason,"$|��a| = ��|a|$");
  return 0;
}

/*_______________________________________________________________________*/
MEXPORT_ALGEBRA int cancelabs3(term t, term arg, term *next, char *reason)
/* example:  |((x-y)(x+y)|/ |(x-y)| =|(x+y)|
Similar to cancelsqrt3 and cancelroot3 */
{ int err = cancel_abs(t,next);
  if(err)
     return 1;
  if(FRACTION(*next))
     strcpy(reason, "|ab|/|ac| = |b|/|c|");
  else
     strcpy(reason," |ab|/|a| = |b|");
  if(PRIME(t))
     SETPRIME(*next);
  HIGHLIGHT(*next);
  return 0;
}

/*___________________________________________________________________*/
 /*   |ab|=|a||b|  */
MEXPORT_ALGEBRA int absofproduct(term t, term arg, term *next, char *reason)
{ term u;
  unsigned short n;
  int i;
  if(FUNCTOR(t) != ABS)
     return 1;
  if(FUNCTOR(ARG(0,t)) != '*')
     return 1;
  u = ARG(0,t);
  n = ARITY(u);
  *next = make_term('*',n);
  for(i=0;i<n;i++)
     ARGREP(*next,i,abs1(ARG(i,u)));
  strcpy(reason,english(304));  /* |uv|=|u||v| */
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_ALGEBRA int multabs(term t, term arg, term *next, char *reason)
/*   a|b|=|ab| if  0 � a */

{ term a,b,u;
  unsigned short n;
  int i,j,err;
  if(FUNCTOR(t) != '*')
     return 1;
  n = ARITY(t);
  /* identify the (first) ABS factor */
  for(i=0;i<n;i++)
     { if(FUNCTOR(ARG(i,t)) == ABS)
          break;
     }
  if(i==n)
     return 1;   /* no ABS factor */
  b = ARG(0,ARG(i,t));
  if(n == 2)
     a = ARG(i ? 0 : 1, t);
  else
     { a = make_term('*',(unsigned short)(n-1));
       for(j=0;j<n-1;j++)
          ARGREP(a,j,ARG(j<i? j : j+1,t));
     }
  err = infer(lessthan(zero,a));
  if(err)
     { errbuf(0,english(1445));
       /* Coefficient must be nonnegative. */
       return 1;
     }
  u = make_term('*',n);
  for(j=0;j<n;j++)
     ARGREP(u,j,j==i ? b : ARG(j,t));
  *next = abs1(u);
  strcpy(reason,english(2221)); /* $a|b| = |ab|$ if $0 � a$ */
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_ALGEBRA int divabs(term t, term arg, term *next, char *reason)
/* |b|/c=|b/c| if  0 < c */

{ term b,c,num;
  int err;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  c = ARG(1,t);
  if(FUNCTOR(num) != ABS)
     return 1;
  b = ARG(0,num);
  err = infer(lessthan(zero,c));
  if(err)
     { errbuf(0,english(1446));
          /* Denominator must be positive. */
       return 1;
     }
  *next = abs1(make_fraction(b,c));
  strcpy(reason,"|b|/c = |b/c| if 0<c");
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_ALGEBRA int divabs2(term t, term arg, term *next, char *reason)
/*   a|b|/c=|ab/c| if  0 < a/c */

{ term a,b,c,num,u;
  unsigned short n;
  int i,j,err;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  c = ARG(1,t);
  if(FUNCTOR(num) != '*')
     return 1;
  n = ARITY(num);
  /* identify the (first) ABS factor */
  for(i=0;i<n;i++)
      { if(FUNCTOR(ARG(i,num)) == ABS)
           break;
      }
  if(i==n)
     return 1;   /* no ABS factor */
  b = ARG(0,ARG(i,num));
  if(n == 2)
     a = ARG(i ? 0 : 1, num);
  else
     { a = make_term('*',(unsigned short)(n-1));
       for(j=0;j<n-1;j++)
          ARGREP(a,j,ARG(j<i? j : j+1,num));
     }
  err = infer(lessthan(zero,product(a,c)));
  /* save one step in infer(lessthan(zero,make_fraction(a,c))) */
  if(err)
     { errbuf(0,english(1447));
       /* a/c must be positive. */
       return 1;
     }
  u = make_term('*',n);
  for(j=0;j<n;j++)
     ARGREP(u,j,j==i ? b : ARG(j,num));
  *next = abs1(make_fraction(u,c));
  strcpy(reason, english(2222));  /* a|b|/c = |ab/c|      if $0�a/c$ */
  HIGHLIGHT(*next);
  return 0;
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int abseqntoineq1(term t, term arg, term *next, char *reason)
/* abs(u) = u =>  0 <= u */
{ term u;
  if(FUNCTOR(t) != '=' || FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  u = ARG(0,ARG(0,t));
  if(!equals(ARG(1,t),u))
     return 1;
  *next = le(zero,u);
  HIGHLIGHT(*next);
  strcpy(reason, english(2188));   /* |u| = u iff 0 � u */
  return 0;
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int abseqntoineq2(term t, term arg, term *next, char *reason)
/* abs(u) = -u =>  u <= 0 */
{ term u,v,w;
  if(FUNCTOR(t) != '=' || FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  u = ARG(0,ARG(0,t));
  v = ARG(1,t);
  polyval(sum(u,v),&w);
  if(!ZERO(w))
     return 1;
  *next = le(u,zero);
  HIGHLIGHT(*next);
  strcpy(reason, english(2189));   /* |u| = -u iff u � 0 */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absineqtrue2(term t, term arg, term *next, char *reason)
/* -c�|u| is true (c�0) */
{ int err;
  if(FUNCTOR(t) != LE)
     return 1;
  if(FUNCTOR(ARG(1,t)) != ABS)
     return 1;
  err = infer(le(ARG(0,t),zero));
  if(err)
     return 1;
  *next = true;
  HIGHLIGHT(*next);
  strcpy(reason, english(1695));  /* -c�|u| is true (c�0) */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absineqtrue3(term t, term arg, term *next, char *reason)
/* -c < |u| is true (c > 0) */
{ int err;
  if(FUNCTOR(t) != '<')
     return 1;
  if(FUNCTOR(ARG(1,t)) != ABS)
     return 1;
  err = infer(lessthan(ARG(0,t),zero));
  if(err)
     return 1;
  *next = true;
  HIGHLIGHT(*next);
  strcpy(reason, english(1696));  /* -c<|u| is true (c>0) */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absineqtrue2g(term t, term arg, term *next, char *reason)
/* |u| � -c is true (c�0) */
{ int err;
  if(FUNCTOR(t) != GE)
     return 1;
  if(FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  err = infer(le(ARG(1,t),zero));
  if(err)
     return 1;
  *next = true;
  HIGHLIGHT(*next);
  strcpy(reason, english(1709));  /* |u|�-c is true (c�0) */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absineqtrue3g(term t, term arg, term *next, char *reason)
/* |u| > -c is true (c>0) */
{ int err;
  if(FUNCTOR(t) != '>')
     return 1;
  if(FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  err = infer(lessthan(ARG(1,t),zero));
  if(err)
     return 1;
  *next = true;
  HIGHLIGHT(*next);
  strcpy(reason, english(1710)); /* |u|>-c is true (c>0) */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int abslessthanneg(term t, term arg, term *next, char *reason)
/* |u| < -c has no solution if c � 0 */
{ int err;
  if(FUNCTOR(t) != '<')
     return 1;
  if(FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  err = infer(le(ARG(1,t),zero));
  if(err)
     return 1;
  *next = false;
  HIGHLIGHT(*next);
  strcpy(reason, english(1697)); /* |u|<-c has no solution    if c�0 */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absleneg(term t, term arg, term *next, char *reason)
/* |u| � -c has no solution if c > 0 */
{ int err;
  if(FUNCTOR(t) != LE)
     return 1;
  if(FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  err = infer(lessthan(ARG(1,t),zero));
  if(err)
     return 1;
  *next = false;
  HIGHLIGHT(*next);
  strcpy(reason, english(1698)); /* |u|�-c has no solution    if c>0 */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int abseqnneg(term t, term arg, term *next, char *reason)
/* |u| = -c iff u = 0 (assuming c = 0) */
{ if(FUNCTOR(t) != '=')
     return 1;
  return absleneg2(t,arg,next,reason);
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absleneg2(term t, term arg, term *next, char *reason)
/* |u| � -c iff u = 0 (assuming c = 0) */
/* Example:  |x^3-x| � -x^2.  In MathXpert you can't convert this
to x^3-x = 0 and x^2=0, so instead we assume x^2 = 0 and solve
x^3-x = 0; then two solutions are rejected as contradicting x = 0.
*/
{ int err;
  term p;
  if(FUNCTOR(t) != LE && FUNCTOR(t) != '=')
     return 1;
  if(FUNCTOR(t) == '=' && FUNCTOR(ARG(0,t)) != ABS && FUNCTOR(ARG(1,t)) == ABS)
     t = equation(ARG(1,t),ARG(0,t));
  if(FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  err = infer(le(ARG(1,t),zero));
  if(err)
     { errbuf(0, english(1699));  /* The right-hand side must be non-positive */
       return 1;
     }
  err = infer(lessthan(ARG(1,t),zero));
  if(!err)
     { errbuf(0, english(1700));  /* Right hand side can never be zero. */
       return 1;
     }
  p = lpt(equation(ARG(1,t),zero));
  if(!equals(p,true))
     assume(p);
  *next = equation(ARG(0,ARG(0,t)),zero);
  HIGHLIGHT(*next);
  if(FUNCTOR(t) == LE)
     strcpy(reason,english(1701));
     /* |u| � -c iff u = 0 (assuming c = 0) */
  else
     strcpy(reason, english(1720));
     /* |u| = -c iff u = 0    (assuming c = 0) */
  set_checksolutionsflag(1);
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absineqtrueg(term t, term arg, term *next, char *reason)
/* |u| � 0 is true */
{ if(FUNCTOR(t) != GE)
     return 1;
  if(FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  if(!ZERO(ARG(1,t)))
     return 1;
  *next = true;
  HIGHLIGHT(*next);
  strcpy(reason, english(1702)); /* |u| � 0 is true */
  return 0;
}


/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absineqfalseg(term t, term arg, term *next, char *reason)
/* 0 > |u| has no solution */
{ if(FUNCTOR(t) != '>')
     return 1;
  if(FUNCTOR(ARG(1,t)) != ABS)
     return 1;
  if(!ZERO(ARG(0,t)))
     return 1;
  *next = false;
  HIGHLIGHT(*next);
  strcpy(reason, english(1703)); /* 0>|u| has no solution */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absgreaterthanneg(term t, term arg, term *next, char *reason)
/* -c > |u| has no solution (c � 0) */
{ int err;
  if(FUNCTOR(t) != '>')
     return 1;
  if(FUNCTOR(ARG(1,t)) != ABS)
     return 1;
  err = infer(le(ARG(0,t),zero));
  if(err)
     return 1;
  *next = false;
  HIGHLIGHT(*next);
  strcpy(reason, english(1704));
  /* -c > |u| has no      solution (c � 0) */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absgeneg(term t, term arg, term *next, char *reason)
/* -c � |u| has no solution (c > 0) */
{ int err;
  if(FUNCTOR(t) != GE)
     return 1;
  if(FUNCTOR(ARG(1,t)) != ABS)
     return 1;
  err = infer(lessthan(ARG(0,t),zero));
  if(err)
     return 1;
  *next = false;
  HIGHLIGHT(*next);
  strcpy(reason, english(1705));
  /* -c � |u| has no      solution (c > 0) */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int absgeneg2(term t, term arg, term *next, char *reason)
/* -c � |u| iff u = 0, assuming c = 0 */
{ int err;
  term p;
  if(FUNCTOR(t) != GE)
     return 1;
  if(FUNCTOR(ARG(1,t)) != ABS)
     return 1;
  err = infer(le(ARG(0,t),zero));
  if(err)
     { errbuf(0, english(1706));  /* The left-hand side must be non-positive */
       return 1;
     }
  err = infer(lessthan(ARG(0,t),zero));
  if(!err)
     { errbuf(0, english(1707));  /* Left-hand side can never be zero. */
       return 1;
     }
  p = lpt(equation(ARG(0,t),zero));
  if(!equals(p,true))
     assume(p);
  *next = equation(ARG(0,ARG(1,t)),zero);
  HIGHLIGHT(*next);
  strcpy(reason,english(1708));
  /* -c � |u| iff u = 0, (assuming c = 0)  */
  set_checksolutionsflag(1);
  return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int introduceabs(term t, term arg, term *next, char *reason)
/* [p = a, p = -a] becomes p = abs(a) if p >= 0 and the sign of
a cannot be determined.  Example, [x^2 = a, x^2 = -a] becomes
x^2 = abs(a).  Without this operation, MathXpert will solve the
equation (x^2-a)(x^2+a) = 0 and get four square roots with the
assumptions a >= 0 and a <= 0.  With it, it will get x = sqrt(abs(a))
and x = -sqrt(abs(a)) with no assumption on a.
*/
{ unsigned short n;
  int i,j,k,err;
  term u,v,p,a,b,temp;
  if(FUNCTOR(t) != OR)
     return 1;
  if(iscomplex(t))
     return 1;
     /* this leads to wrong results e.g. on [x^2 = i, x^2 = -i] */
  n = ARITY(t);
  if(n == 2)
     { u = ARG(0,t);
       v = ARG(1,t);
       if(FUNCTOR(u) != '=' || FUNCTOR(v) != '=')
           return 1;
       p = ARG(0,u);
       if(!equals(p,ARG(0,v)))
          return 1;
       a = ARG(1,u);
       b = ARG(1,v);
       if(
          !(NEGATIVE(a) && equals(ARG(0,a),b)) &&
          !(NEGATIVE(b) && equals(ARG(0,b),a)) &&
          !(
            FUNCTOR(a) == '+' && FUNCTOR(b) == '+' &&
            ARITY(a) == ARITY(b) && equals(strongnegate(a),b)
           )
         )
          return 1;
       if(obviously_nonnegative(a) || obviously_nonnegative(b))
          return 1;
       if(!infer(nonnegative(a)) || !infer(nonnegative(b)))
          return 1;
       *next = equation(p,abs1(NEGATIVE(a) ? ARG(0,a) : a));
       strcpy(reason, english(2187));
         /* [p=a,p=-a] and p�0   iff p=|a| */
       return 0;
     }
  /* Now n > 2 */
  u = make_term(OR,2);
  for(i=0;i<n;i++)
     { for(j=i+1;j<n;j++)
          { ARGREP(u,0,ARG(i,t));
            ARGREP(u,1,ARG(j,t));
            err = introduceabs(u,arg,&temp,reason);
            if(!err)
               goto success;
          }
     }
  RELEASE(u);
  return 1;
  success:
  *next = make_term(OR,(unsigned short)(n-1));
  for(k=0;k<n-1;k++)
     ARGREP(*next,k, k<i ? ARG(k,t) : k==i ? temp : k<j ? ARG(k,t) : ARG(k+1,t));
  return 0;
}
/*_______________________________________________________*/
MEXPORT_ALGEBRA int intervaltoabs1(term t, term arg, term *next, char *reason)
/* -a <= u <= a iff |u| <= a */
{ term u,a;
  if(!interval_as_and(t))
     return 1;
  if(FUNCTOR(ARG(0,t)) != LE || FUNCTOR(ARG(1,t)) != LE)
     return 1;
  u = ARG(0,ARG(1,t));
  a = ARG(1,ARG(1,t));
  if(!NEGATIVE(ARG(0,ARG(0,t))))
     return 1;
  if(!equals(a,ARG(0,ARG(0,ARG(0,t)))))
     return 1;
  *next = le(abs1(u),a);
  strcpy(reason, english(2421)); /* $-a \\le u \\le a$ iff $|u|\\le a$ */
  return 0;
}

/*_______________________________________________________*/
MEXPORT_ALGEBRA int intervaltoabs2(term t, term arg, term *next, char *reason)
/* -a < u <= a iff |u| < a */
{ term u,a;
  if(!interval_as_and(t))
     return 1;
  if(FUNCTOR(ARG(0,t)) != '<' || FUNCTOR(ARG(1,t)) != '<')
     return 1;
  u = ARG(0,ARG(1,t));
  a = ARG(1,ARG(1,t));
  if(!NEGATIVE(ARG(0,ARG(0,t))))
     return 1;
  if(!equals(a,ARG(0,ARG(0,ARG(0,t)))))
     return 1;
  *next = le(abs1(u),a);
  strcpy(reason, english(2422));  /* $-a < u < a$ iff $|u|<a$ */
  return 0;
}

/*_______________________________________________________*/
MEXPORT_ALGEBRA int absevenpowerrev(term t, term arg, term *next, char *reason)
/* u^(2n) = |u|^(2n) if u is real     */
{ if(FUNCTOR(t) != '^')
     return 1;
  if(!iseven(ARG(1,t)))
     return 1;
  if(iscomplex(t))
     return 1;
  *next = make_power(abs1(ARG(0,t)),ARG(1,t));
  strcpy(reason, "$u^(2n)=|u|^(2n)$ if u is real");
  return 0;
}
/*_______________________________________________________*/
MEXPORT_ALGEBRA int abspowerrev(term t, term arg, term *next, char *reason)
/* |u|^n = |u^n| if u is real     */
{ if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != ABS)
     return 1;
  if(iscomplex(ARG(1,t)))
     return 1;
  *next = abs1(make_power(ARG(0,ARG(0,t)),ARG(1,t)));
  strcpy(reason, "$|u|^n = |u^n|$ if u is real");
  return 0;
}

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