Sindbad~EG File Manager

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

/* menu operators for exponents menu */
/* M. Beeson
original date 12.14.90
last modified 3.12.99
*/

#define ALGEBRA_DLL
#include <string.h>
#include <assert.h>
#include <math.h>

#include "globals.h"
#include "ops.h"
#include "checkarg.h"  /* otherwise model.h won't compile */
#include "prover.h"
#include "order.h"
#include "cancel.h"
#include "simpprod.h"
#include "probtype.h"
#include "eqn.h"      /* econstant */
#include "algaux.h"   /* contains_monomially */
#include "pvalaux.h"  /* contains_neg_exp     */
#include "symbols.h"
#include "mathmode.h"   /* get_mathmode   */
#include "exponent.h"   /* possible_int   */
#include "errbuf.h"
#include "pathtail.h"   /* set_pathtail   */
#include "autosimp.h"   /* SetShowStepOperation */
#include "trig.h"       /* factorbase     */
#include "nfactor.h"    /* factor_integer */
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int zeroexponent(term t, term arg, term *next, char *reason)
{ if(FUNCTOR(t) != '^')
     return 1;
  if(!ZERO(ARG(1,t)))
     return 1;
  if(contains(ARG(0,t),LIMIT))
     { errbuf(0, english(747));
       /* First evaluate the limit to be sure it is not zero. */
       return 1;
     }
  if(get_polyvaldomainflag() && infer(nonzero(ARG(0,t))))
     /* check for 0^0 */
     return 1;
  *next = one;
  HIGHLIGHT(*next);
  strcpy(reason,"a^0 = 1");
  return 0;
}

/* Example:  consider (1/x)^0 = 1.  The domains are different.
When we go to solve the equation x+1 = (1/x)^0  we should reject x = 0.
This will be OK because the original domain check will assume x != 0.
*/
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int unitexponent(term t, term arg, term *next, char *reason)
{ if(FUNCTOR(t) != '^'  || !ISONE(ARG(1,t)) )
     return 1;
  *next = ARG(0,t);
  HIGHLIGHT(*next);
  strcpy(reason,"a^1 = a");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int writeintegeraspower(term t, term arg, term *next, char *reason)
/* If t is an integer, write it in the form a^b if possible, e.g.
36 = 6^2.
   Also works on  t^log(b,c)  when t is a power of b.
   Also on t^u when u contains log(b,c) somewhere.
   Also on an equation or inequality of the form n^... = m^...
*/
{ term a,b,u,v;
  unsigned nfactors;
  term factors,cancelled,temp,temp2,z,q,p1,p2;
  unsigned short path[5];
  int err,err1 = 1,err2 = 1;
  unsigned short i;
  unsigned short f = FUNCTOR(t);
  if(INEQUALITY(f))
     { u = ARG(0,t);
       v = ARG(1,t);
       if(FUNCTOR(u) == '^' &&
          ISINTEGER(ARG(0,u)) &&
          !constant(ARG(1,u)) &&
          FUNCTOR(v) == '^' &&
          ISINTEGER(ARG(0,v)) &&
          !constant(ARG(1,v)) &&
          (err1 = writeintegeraspower(ARG(0,u),arg,&temp,reason)) == 0 &&
          (err2 = writeintegeraspower(ARG(0,v),arg,&temp2,reason)) == 0 &&
          FUNCTOR(temp) == '^' && FUNCTOR(temp2) == '^' &&
          equals(ARG(0,temp),ARG(0,temp2)) &&
          !gcd(ARG(1,temp),ARG(1,temp2),&z) &&
          !ONE(z)
         )
          { /* example:  4^... = 256^...
               we want to write 256 as a power of 4 rather than
               write both 4 and 256 as powers of 2.
               In the example, temp  = 2^2 and temp2 = 2^8;
               z = gcd(2,8) = 2.
            */
            value(make_power(ARG(0,temp),z),&q);
            if(equals(z,ARG(1,temp)))
               { /* as it is in the example; then we only rewrite the
                    right side of the equation */
                 value(make_fraction(ARG(1,temp2),z),&p2);
                 temp2 = make_power(q,p2);
                 *next = equation(u,make_power(temp2,ARG(1,v)));
                 path[0] = f;
                 path[1] = 2;
                 path[2] = '^';
                 path[3] = 1;
                 path[4] = 0;
                 set_pathtail(path);
                 SetShowStepOperation(writenumberaspowerof);
                 return 0;
               }
            else
               { /* then only rewrite the left side;
                    the right side will be rewritten in a separate step
                 */
                 value(make_fraction(ARG(12,temp),z),&p1);
                 temp = make_power(q,p1);
                 *next = equation(make_power(temp,ARG(1,u)),v);
                 path[0] = f;
                 path[1] = 1;
                 path[2] = '^';
                 path[3] = 1;
                 path[4] = 0;
                 set_pathtail(path);
                 SetShowStepOperation(writenumberaspowerof);
                 return 0;
               }
          }
       if(FUNCTOR(u) == '^' &&
          ISINTEGER(ARG(0,u)) &&
          !constant(ARG(1,u))
         )
          { if(err1)
               err1 = writeintegeraspower(ARG(0,u),arg,&temp,reason);
            if(!err1)
               { path[0] = f;
                 path[1] = 1;
                 path[2] = '^';
                 path[3] = 1;
                 path[4] = 0;
                 set_pathtail(path);
                 *next = equation(make_power(temp,ARG(1,u)),v);
                 return 0;
               }
          }
       if(FUNCTOR(v) == '^' &&
          ISINTEGER(ARG(0,v)) &&
          !constant(ARG(1,v))
         )
          { if(err2)
               err2 = writeintegeraspower(ARG(0,v),arg,&temp,reason);
            if(err2)
               return 1;
            path[0] = f;
            path[1] = 2;
            path[2] = '^';
            path[3] = 1;
            path[4] = 0;
            set_pathtail(path);
            *next = equation(u,make_power(temp,ARG(1,v)));
            return 0;
          }
       return 1;
     }
  if(f == '^' && ISINTEGER(ARG(0,t)) && contains(ARG(1,t),LOGB))
     { u = ARG(0,t);
       v = ARG(1,t);
       err = writeintegeraspower(u,arg,&temp,reason);
       if(err)
          return 1;
       *next = make_power(temp,v);
       path[0] = '^';
       path[1] = 1;
       path[2] = 0;
       set_pathtail(path);
       return 0;
     }
  if(!INTEGERP(t))
     return 1;
  err = factor_integer(t,&nfactors,&factors);
  if(err)
     return 1;
  if(nfactors == 1 && FUNCTOR(factors) == '^')
     { a = ARG(0,factors);
       b = ARG(1,factors);
       *next = make_power(a,b);
       HIGHLIGHT(*next);
       strcpy(reason, english(1840));  /* write integer as a^n */
       return 0;
     }
  /* Now nfactors > 1 */
  /* example:  36 = 6^2, ARG(0,t) = 36, we want a = 6, b = 2 */
  /* 36 = 2^2 3^2. b is the gcd of the exponents in the prime
     factorization.  */
  for(i=0;i<nfactors;i++)
     { if(FUNCTOR(ARG(i,factors)) != '^')
          return 1;
     }
  /* Now each prime has a nontrivial exponent */
  b = ARG(1,ARG(0,factors));
  for(i=1;i<nfactors;i++)
     { gcd(b,ARG(1,ARG(i,factors)),&temp);
       b = temp;
       if(ONE(b))
          return 1;
     }
  /* That determines b */
  /* Now determine a by cancelling b out of each exponent in turn */
  a = make_term('*', (unsigned short) nfactors);
  for(i=0;i<nfactors;i++)
     { cancel(ARG(1,ARG(i,factors)),b,&cancelled,&u);
       ARGREP(a,i,make_power(ARG(0,ARG(i,factors)),u));
     }
  value(a,&u);
  a = u;
  *next = make_power(a,b);
  HIGHLIGHT(*next);
  strcpy(reason, english(1840));  /* write integer as a^n */
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int writeassum(term t, term arg, term *next, char *reason)
/* x = ? + (x-?) */
{ term u,v;
  int err;
  if(FUNCTOR(arg) == ILLEGAL)
     return 1;
  u = sum(t, tnegate(arg));
  err = value(u,&v);
  if(err && err != 2)
  v = u;
  *next = sum(arg,v);
  HIGHLIGHT(*next);
  strcpy(reason, "x = y + (x-y)");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int powertopower(term t, term arg, term *next, char *reason)
/* (a^b)^c = a^(bc) if a > 0 or c is an integer, or a >= 0 and b>0 and c>0 */
/* also when a^b is an integer not in factored form and c is a
fractional exponent whose denom will cancel with b.
   Also when b and c are rational numbers such that 2 does not cancel
in bc; see polyval.c for a full explanation.  Examples,
b = 4, c = 1/5 works fine;  b = 2, c = 1/2 does not work.
   The above conditions are for real arguments.  When complex numbers are 
involved the conditions are more complicated. For example (e^b)^c = e^bc
only if -pi <=  b <= pi.   eg. sqrt(e^( 3pi/2 i )) is e^-(pi/4 i), not e^(3pi/4 i).
*/
{ term a,b,c,power,q,u,v,temp;
  int err;
  unsigned short path[5];
  unsigned short f = FUNCTOR(t);
  if(INEQUALITY(f))
     /* work on the sides of an equation */
     { u = ARG(0,t);
       v = ARG(1,t);
       if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == '^')
          { err = powertopower(u,arg,&temp,reason);
            if(!err)
               { path[0] = f;
                 path[1] = 1;
                 path[2] = 0;
                 set_pathtail(path);
                 *next = equation(temp,v);
                 return 0;
               }
          }
       if(FUNCTOR(v) == '^' && FUNCTOR(ARG(0,v)) == '^')
          { err = powertopower(v,arg,&temp,reason);
            if(err)
               return 1;
            path[0] = f;
            path[1] = 2;
            path[2] = 0;
            set_pathtail(path);
            *next = equation(u,temp);
            return 0;
          }
       return 1;
     }
  if(FUNCTOR(t) != '^')
     return 1;
  if(INTEGERP(ARG(0,t)) && RATIONALP(ARG(1,t)) && get_mathmode() == AUTOMODE)
     { err = writeintegeraspower(ARG(0,t),arg,&q,reason);
       if(err)
          return 1;
       SetShowStepOperation(writeintegeraspower);
       path[0] = '^';
       path[1] = 1;
       path[2] = 0;
       set_pathtail(path);
       *next = make_power(q,ARG(1,t));
       return 0;
     }
  else if(FUNCTOR(ARG(0,t)) == '^')
     { a = ARG(0,ARG(0,t));
       b = ARG(1,ARG(0,t));
       c = ARG(1,t);        /*  t = (a^b)^c  */
       release(arithmetic);   /* possibly inhibited by factorbase (in arith.c) */
       if(isinteger(c))
          err = 0;
       if(is_complex(a) && (!isinteger(c) || !isinteger(b)))
           { errbuf(0,english(2470));
             return 1;  /* "first write a in polar form" */
           }
       else if(obviously_positive(a))
          { if(isinteger(c) || !is_complex(b))
               err = 0;
            else 
               { term p,theta;
                 err = complexparts(b,&p,&theta);
                 if(!err)
                    { err = infer(and(lessthan(tnegate(pi),theta),lessthan(theta,pi)));
                    }
                 if(err)
                    { errbuf(0,english(2469));
                      /*  (a^b)^c = a^(bc) only when -pi <= arg b <= pi  */
                      return 1;
                    }
               }
          }
       else if(FRACTION(c) && isinteger(ARG(0,c)) && isinteger(ARG(1,c)) &&
               isinteger(b) &&
               (isodd(ARG(1,c)) || isodd(b))
              )
          err = 0;
       else if(FRACTION(b) && FRACTION(c) &&
               isinteger(ARG(0,b)) && isinteger(ARG(1,b)) &&
               isinteger(ARG(0,c)) && isinteger(ARG(1,c)) &&
               (isodd(ARG(1,c)) || isodd(ARG(0,b))) &&
               (isodd(ARG(0,c)) || isodd(ARG(1,b)))
              )
          err = 0;

       else if(obviously_positive(b) && obviously_positive(c))
          err = check(le(zero,a));
       else
          err = check(or(type(c,INTEGER),positive(a))); /* to prevent ((-1)^2)^(1/2)= -1 */
       if(err)
         { errbuf(0, english(442));
               /* That law is valid only when a>0 or c is an integer. */
           errbuf(1, english(443));
               /* For example, ((-1)^2)^� is 1, not -1 */
           return 1;
         }
       power = product(b,c);
       if(numerical(power) && status(powertopower) >= KNOWN)
          /* then evaluate the new power */
          { err = value(power,&q);
            if(err == 0 || err == 2)
                power = q;
          }
     }
  else
     return 1;
  /* success:  */
  *next = make_power(a,power);
  HIGHLIGHT(*next);
  strcpy(reason,"(a^b)^c = a^(bc)");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int minustopower(term t, term arg, term *next, char *reason)
/* (-a)� = (-1)�a� if a� is defined */
{ term a,b,n;
  int err;
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != '-')
     return 1;
  a = ARG(0,ARG(0,t));
  n = ARG(1,t);     /*  t = (-a)�  */
  if (ISONE(a))
     return 1;
  b = make_power(a,n);
  if(OBJECT(a) || INTEGERP(n) || (RATIONALP(n) && ISODD(ARG(1,n))))
     err = 0;  /* avoid calling check in simple cases */
  else
     err = check(defined(b));
  if(err)
     { errbuf(0, english(748));
       /* That would create an undefined power */
       return 1;
     }
  *next = product(make_power(tnegate(one),n),make_power(a,n));
  HIGHLIGHT(*next);
  strcpy(reason,"$(-a)� = (-1)�a�$");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int quotienttopower(term t, term arg, term *next, char *reason)
{ term a,b,c,tempnum,num,tempdenom,denom,x,p;
  int problemtype;
  int i,err;
  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);  /* (a/b)^c  */
  if(!OBJECT(c) && get_polyvaldomainflag())
     /* check if c is defined */
     { if(contains_undefined(c))
          { errbuf(0, english(739));
            /* You can't apply that law when the exponent is not defined. */
            return 1;
          }
       if(contains(c,LIMIT))
          { errbuf(0, english(740));
            /* You must first evaluate the limit in the exponent. */
            return 1;
          }
       if(contains(c,INTEGRAL))
          { errbuf(0, english(741));
            /* You must first evaluate the integral in the exponent. */
            return 1;
          }
       err = check(defined(c));
       if(err)
          { errbuf(0, english(739));
            return 1;
          }
     }
  if(ZERO(b) && iseven(c))
     { tempdenom = make_term('^',2);
       ARGREP(tempdenom,0,b);
       ARGREP(tempdenom,1,c);
       /* make_power will produce zero */
     }
  else
     tempdenom = make_power(b,c);
  tempnum = make_power(a,c);
  if(status(quotienttopower) > LEARNING)
    { err = value(tempdenom,&denom);
      if(err==1 || ZERO(denom))
        denom = tempdenom;
      err = value(tempnum,&num);
      if(err==1)
         num = tempnum;
    }
  else
     { num = tempnum;
       denom = tempdenom;
     }
  if(!INTEGERP(c) && !(RATIONALP(c) && ISODD(ARG(1,c))))
     { problemtype = get_problemtype();
       x = get_eigenvariable();
       for(i=0;i<2;i++)
          { p = i ? denom : num;
            if(FUNCTOR(p) != '^')
               continue;  /* value evaluated it above then */
            if(obviously_nonnegative(ARG(0,p)))
               err = 0;
            else if(FRACTION(c) && isinteger(ARG(0,c)) && ISINTEGER(ARG(1,c)) && isodd(ARG(1,c)))
               err = 0;
            else
               err = check(le(zero,ARG(0,p)));
               /* not check(domain(p))  which leads to really complicated assumptions */
            if(err)
               { if(SOLVETYPE(problemtype) && contains(num,FUNCTOR(x)))
                    { errbuf(0, english(1806));
                      errbuf(1, english(1807));
                      errbuf(2, english(1808));
                      /* To ensure that the result is defined, you would have to make assumptions involving the variable.
                         That might cause you to lose solutions, and hence is not allowed. */
                      return 1;
                    }
                 errbuf(0, english(i ? 750 : 749));
                 /* The new numerator would be undefined. */
                 /* The new denominator would be undefined. */
                 return 1;
               }
          }
     }
  *next =  make_fraction(num,denom);
  HIGHLIGHT(*next);
  if(SOME_INFINITESIMAL(ARG(0,t)))
     { if(POSITIVE_INFINITESIMAL(ARG(0,t)))
          SETPOSITIVE(*next);
       if(NEGATIVE_INFINITESIMAL(ARG(0,t)))
          SETNEGATIVE(*next);
     }
  strcpy(reason, "$(a/b)� = a�/b�$");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int producttopower(term t, term arg, term *next, char *reason)
/* (ab)� = a�b� */
{ term u,v,n,w,power2;
  int i,err;
  char buffer[DIMREASONBUFFER];
  if(FRACTION(t) && numerical(t))
     { return factorbase(t,arg,next,reason);
     }
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  if(INTEGERP(u))
     { v = ARG(1,t);
       w= make_term('^',2);
       err = factorinteger(u,arg,ARGPTR(w),buffer);
       if(err)
          return 1;
       ARGREP(w,1,v);
       err = producttopower(w,arg,next,reason);
       if(err)
          return 1; /* assert(0) */
       return 0;
     }
  if(FUNCTOR(u) != '*')
     return 1;
  n = ARG(1,t);
  *next = make_term('*',ARITY(u));
  if(equals(n,two))
     { for(i=0;i<ARITY(u);i++)
          ARGREP(*next,i,square(ARG(i,u)));
     }
  else
     { int st = status(producttopower);
       for(i=0;i<ARITY(u); i++)
          { v = ARG(i,u);
            if(!ATOMIC(n))
               copy(n,&power2);  /* avoid creating DAGs */
            else
               power2 = n;
            if(st==WELLKNOWN && numerical(v) &&
               ISINTEGER(n) && INTDATA(n) < 10
              )
               { err = value(make_power(v,n),ARGPTR(*next)+i);
                 if(err)
                    ARGREP(*next,i,make_power(v,n));
               }
            else if(INTEGERP(n) ||
                    get_complex() ||
                    (NEGATIVE(n) && INTEGERP(ARG(0,n))) ||
                    (RATIONALP(n) && ISODD(ARG(1,n))) ||
                    (NEGATIVE(n) && RATIONALP(ARG(0,n)) && ISODD(ARG(1,ARG(0,n))))
                   )
               ARGREP(*next,i,make_power(v,power2));
            else if(RATIONALP(n))
               { err = check(le(zero,v));
                 if(err)
                    { errbuf(0, english(1123));
                        /* (ab)�=a�b� requires a� and b� defined. */
                      RELEASE(*next);
                      return 1;
                    }
                 ARGREP(*next,i,make_power(v,power2));
               }
            else
               { term w = make_power(v,power2);
                 err = check(domain(w));
                 if(err)
                    { errbuf(0, english(1123));
                        /* (ab)�=a�b� requires a� and b� defined. */
                       RELEASE(*next);
                      return 1;
                    }
                 ARGREP(*next,i,w);
               }
          }
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$(ab)� = a�b�$");
  release(arithmetic);  /* inhibited perhaps by factorbase, as in
                    35^(1/3) = (5�7)^(1/3) = 5^(1/3) 7^(1/3)   */
  return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int negexpofquotient(term t, term arg, term *next, char *reason)
/*  (a/b)^(-n) = (b/a)� */
{ term a,b,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(!NEGATIVE(ARG(1,t)))
     return 1;
  if(!FRACTION(ARG(0,t)))
     return 1;
  a = ARG(0,ARG(0,t));
  b = ARG(1,ARG(0,t));
  n = ARG(0,ARG(1,t));
  if(ONE(n))
     { *next = make_fraction(b,a);
       strcpy(reason,"(a/b)^(-1) = b/a");
     }
  else
     { *next = make_power(make_fraction(b,a),n);
       strcpy(reason, "$(a/b)^(-n) = (b/a)�$");
     }
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int eliminatenegexp(term t, term arg, term *next, char *reason)
/*  a^(-n) = 1/a�,
     a^(-n)/b = 1/(a�b), and
     a/b^(-n) = ab�
If learning(negative_exponents), then the first
clause will always be used.  But otherwise, it won't be used on terms
occurring in products or quotients, e.g.   x�y^(-2)z will go directly
to x�z/y^2, and x^2y^(-2) will go to x^2/y^2.

If there are still negative exponents INSIDE t, then fail.  We should
eliminate the INNERMOST negative exponents first, as in
(a^(-1)b^(-2)^(-2).  But this applies only if negexpflag == -1,
i.e. we are eliminating ALL negative exponents.
*/
{ int err,err2,i;
  int somethingdone = 0;
  unsigned short count,k;
  unsigned short n,f;
  term num,denom;
  term a,b,u,temp;
  int statusflag = status(eliminatenegexp);
  int negexpflag = get_polyvalnegexpflag();
  if(statusflag <= LEARNING)  /* only  use a^(-n) = 1/a^n */
     { if(FUNCTOR(t) != '^')
          return 1;
       if(FUNCTOR(ARG(1,t)) != '-')
          return 1;
     }
  if(FUNCTOR(t)=='^')
     {  a = ARG(0,t);
        b = ARG(1,t);
        if(negexpflag == -1 &&
            (contains_neg_exp(a) || contains_neg_exp(b) )
          )
           return 1;   /* fail, eliminate the inside negexp first */
        err = negexp_aux(t,&u);
        if(err)
           return 1;
        if(ONE(u))
           { SetShowStepOperation(eliminatenegexp1);
             *next = reciprocal(a);
             strcpy(reason,"$a^(-1) = 1/a$");
             return 0;
           }
        *next = reciprocal(make_power(a,u));
        HIGHLIGHT(*next);
        strcpy(reason,"$a^(-n) = 1/a�$");
        return 0;
     }
  if(FUNCTOR(t)=='*' && status(eliminatenegexp) > LEARNING)
     { n = ARITY(t);
       num = make_term('*',n);  /* be sure to have enough space */
       denom = make_term('*',n);
       count = 0;        /* count the negative exponents in t */
       k = 0;            /* mark the place in num */
       if(negexpflag==-1)
          { for(i=0;i<n;i++)
               { if(contains_neg_exp(ARG(i,t)))
                    return 1;
                    /* fail, should eliminate the inside neg exp first */
               }
          }
      for(i=0;i<n;i++)
         { arg = ARG(i,t);
           f = FUNCTOR(arg);
           if(f == '^' || f == '/')
              { a = ARG(0,arg);
                b = ARG(1,arg);
              }
           if( f == '^' && !negexp_aux(arg,&u))
              { ARGREP(denom,count,make_power(a,u));
                HIGHLIGHT(ARG(count,denom));
                ++ count;
                ++ somethingdone;
              }
           else if(f == '/')   /* (a/b)c^(-n) = a/(bc�)  */
              { if(!ONE(a))
                   { ARGREP(num,k,a);
                     ++k;
                   }
                ARGREP(denom,count,b);
                ++count;
              }
           else
              { ARGREP(num,k,arg);
                ++k;
              }
         }
      SETFUNCTOR(num,'*',k);
      SETFUNCTOR(denom,'*',count);
      if(count == 0 || somethingdone == 0)
         { RELEASE(denom);
           RELEASE(num);
           return 1;
         }
      if(k==0)
         { RELEASE(num);
           num = one;
         }
      if(k==1)
         { temp = ARG(0,num);
           RELEASE(num);
           num = temp;
         }
      if(count == 1)
         { temp = ARG(0,denom);
           RELEASE(denom);
           denom = temp;
         }
      *next = make_fraction(num,denom);
      strcpy(reason,"$a^(-n) = 1/a�$");
      return 0;
     }
  if(FUNCTOR(t)=='/' && status(eliminatenegexp) > LEARNING)
       /* this can only get used in menu mode,
          or when this is called by polyval or limsum3 */
     { term temp;
       err = eliminatenegexpnum(t,arg,&temp,reason);
       if(err)
          temp = t;
       err2 = eliminatenegexpdenom(temp,arg,next,reason);
       if(err2)
          *next = temp;
       if(!err || !err2)
          return 0;
     }
  return 1;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int eliminatenegexp1(term t, term arg, term *next, char *reason)
/*  a^(-1) = 1/a
*/
{ int err;
  term a,b,u;
  int negexpflag = get_polyvalnegexpflag();
  if(FUNCTOR(t) != '^')
     return 1;
  a = ARG(0,t);
  b = ARG(1,t);
  if(negexpflag == -1 &&
     (contains_neg_exp(a) || contains_neg_exp(b) )
    )
     return 1;   /* fail, eliminate the inside negexp first */
  err = negexp_aux(t,&u);
  if(err)
     return 1;
  *next = reciprocal(a);
  HIGHLIGHT(*next);
  strcpy(reason,"a^(-1) = 1/a");
  return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int eliminateconstnegexp(term t, term arg, term *next, char *reason)
/* Like eliminatenegexp but leaves non-constant exponents alone */
{ int err,err2,i;
  int somethingdone = 0;
  unsigned short count,k;
  unsigned short n,f;
  term num,denom;
  term a,b,u,temp;
  int negexpflag = get_polyvalnegexpflag();
  int statusflag = status(eliminatenegexp);
  if(statusflag <= LEARNING)  /* only  use a^(-n) = 1/a^n */
     { if(FUNCTOR(t) != '^')
          return 1;
       if(FUNCTOR(ARG(1,t)) != '-')
          return 1;
     }
  if(FUNCTOR(t)=='^')
     {  a = ARG(0,t);
        b = ARG(1,t);
        if(!constant(b))
           return 1;
        if(negexpflag == -1 &&
            (contains_neg_exp(a) || contains_neg_exp(b) )
          )
           return 1;   /* fail, eliminate the inside negexp first */
        err = negexp_aux(t,&u);
        if(err)
           return 1;
        if(ONE(u))
           { *next = reciprocal(a);
             strcpy(reason,"a^(-1) = 1/a");
             SetShowStepOperation(eliminatenegexp1);
             return 0;
           }
        *next = reciprocal(make_power(a,u));
        HIGHLIGHT(*next);
        strcpy(reason,"$a^(-n) = 1/a�$");
        SetShowStepOperation(eliminatenegexp);
        return 0;
     }
  if(FUNCTOR(t)=='*' && status(eliminatenegexp) > LEARNING)
     { n = ARITY(t);
       num = make_term('*',n);  /* be sure to have enough space */
       denom = make_term('*',n);
       count = 0;        /* count the negative exponents in t */
       k = 0;            /* mark the place in num */
       if(negexpflag==-1)
          { for(i=0;i<n;i++)
               { if(contains_neg_exp(ARG(i,t)))
                    return 1;
                    /* fail, should eliminate the inside neg exp first */
               }
          }
      for(i=0;i<n;i++)
         { arg = ARG(i,t);
           f = FUNCTOR(arg);
           if(f == '^' || f == '/')
              { a = ARG(0,arg);
                b = ARG(1,arg);
              }
           if( f == '^' && !constant(b))
              { ARGREP(num,k,arg);
                ++k;
                continue;
              }
           if( f == '^' && !negexp_aux(arg,&u))
              { ARGREP(denom,count,make_power(a,u));
                HIGHLIGHT(ARG(count,denom));
                ++ count;
                ++ somethingdone;
              }
           else if( f == '/')   /* (a/b)c^(-n) = a/(bc�)  */
              { if(!ONE(a))
                   { ARGREP(num,k,a);
                     ++k;
                   }
                ARGREP(denom,count,b);
                ++count;
              }
           else
              { ARGREP(num,k,arg);
                ++k;
              }
         }
      SETFUNCTOR(num,'*',k);
      SETFUNCTOR(denom,'*',count);
      if(count == 0 || somethingdone == 0)
         { RELEASE(denom);
           RELEASE(num);
           return 1;
         }
      if(k==0)
         { RELEASE(num);
           num = one;
         }
      if(k==1)
         { temp = ARG(0,num);
           RELEASE(num);
           num = temp;
         }
      if(count == 1)
         { temp = ARG(0,denom);
           RELEASE(denom);
           denom = temp;
         }
      *next = make_fraction(num,denom);
      strcpy(reason,"$a^(-n) = 1/a�$");
      return 0;
     }
  if(FUNCTOR(t)=='/' && status(eliminatenegexp) > LEARNING)
       /* this can only get used in menu mode,
          or when this is called by polyval or limsum3 */
     { term temp;
       err = eliminateconstnegexpnum(t,arg,&temp,reason);
       if(err)
          temp = t;
       err2 = eliminatenegexpdenom(temp,arg,next,reason);
       if(err2)
          *next = temp;
       if(!err || !err2)
          return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int introducenegexp(term t, term arg, term *next, char *reason)
/*  a/b� = ab^(-n) */
/* also  a/(bc�d) = ab^(-n)/cd  */

/* Does not work on a/b, there must be an exponent; otherwise e.g.
   a/(1/b�) will be written as a(1/b�)^(-1) instead of a/b^(-n),
   and in x^(3/2) +  1/(x^(5/2)), the EXPONENT in the first term will
   be rewritten, instead of the denominator
   in the second term.
*/

{ term a,b,n,u,v,temp,newnum,newdenom;
  unsigned short k1,k2,i;
  unsigned short k; /* arity of the denom when it's a product */
  unsigned short p;  /* arity of answer when denom is a product */
  if(FUNCTOR(t) != '/')
     return 1;
  if(ISZERO(ARG(0,t)) || SOME_INFINITESIMAL(t))
     return 1;  /* don't apply to an expression with zero denominator */
  if(FUNCTOR(ARG(1,t)) != '^' && FUNCTOR(ARG(1,t)) != '*')
     return 1;
  a = ARG(0,t);
  if(FUNCTOR(ARG(1,t)) == '^')
     { b = ARG(0,ARG(1,t));
       n = ARG(1,ARG(1,t));   /*  so t = a/b�  */
       u = make_power(b,tnegate(n));
       HIGHLIGHT(u);
       *next = product(a,u);
       if(NEGATIVE(n))
          strcpy(reason,"$a/b^(-n) = ab�$");
       else
          strcpy(reason,"$a/b� = ab^(-n)$");
       return 0;
     }
  /* Now the denom is a product */
  b = ARG(1,t);
  k = ARITY(b);
  if(FUNCTOR(a) == '*')
     p = (unsigned short)(ARITY(a)+k);
  else
     p =(unsigned short)(1+k);  /* maximum arity of answer */
  newnum = make_term('*',p);
  if(!ONE(a) && FUNCTOR(a) != '*')
     { ARGREP(newnum,0,a);
       i=1;
     }
  else if(ONE(a))
     i=0;
  else
     { for(i=0;i<ARITY(a);i++)
          ARGREP(newnum,i,ARG(i,a));
     }
  newdenom = make_term('*',k);
  /* Now args from the denom go into newnum or newdenom, according
     as they are powers or not. */
  k1 = i;
  k2 = 0;
  for(i=0;i<k;i++)
    { v = ARG(i,b);
      if(FUNCTOR(v) != '^')
         { ARGREP(newdenom,k2,v);
           ++k2;
         }
      else
         { ARGREP(newnum,k1,make_power(ARG(0,v),tnegate(ARG(1,v))));
           HIGHLIGHT(ARG(k1,newnum));
           ++k1;
         }
    }
  if(k2 == k)  /* there were no powers in the denom */
     { RELEASE(newnum);
       RELEASE(newdenom);
       return 1;
     }
  assert(k1 > 0);
  if(k1 == 1)
     { temp = newnum;
       newnum = ARG(0,newnum);
       RELEASE(temp);
     }
  else
     { SETFUNCTOR(newnum, '*', k1);
       sortargs(newnum);
     }
  if(k2 == 0)
     *next = newnum;
  else if(k2==1)
     { temp = newdenom;
       newdenom = ARG(0,newdenom);
       RELEASE(temp);
       *next = make_fraction(newnum,newdenom);
     }
  else
     { SETFUNCTOR(newdenom,'*',k2);
       sortargs(newdenom);
       *next = make_fraction(newnum,newdenom);
     }
  strcpy(reason,"$a/b� = ab^(-n)$");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int introducenegexp1(term t, term arg, term *next, char *reason)
{ term a,b,n,u;
  if(FUNCTOR(t) != '/')
     return 1;
  if(ISZERO(ARG(0,t)) || SOME_INFINITESIMAL(t))
     return 1;  /* don't apply to an expression with zero denominator */
  a = ARG(0,t);
  b = ARG(1,t);
  n = tnegate(one);
  u=make_power(b,n);
  HIGHLIGHT(u);
  *next = product(a,u);
  strcpy(reason, "a/b = ab^(-1)");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int exponenttosqrt(term t, term arg, term *next, char *reason)
/* convert fractional exponents to sqrts */
{ if(FUNCTOR(t) == '^' && FRACTION(ARG(1,t)) && equals(ARG(1,ARG(1,t)),two))
     return exponenttoroot(t,arg,next,reason);
  if(get_mathmode() != AUTOMODE)
     return backtosqrts(t,arg,next,reason);
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int exponenttoroot(term t, term arg, term *next, char *reason)
/* convert fractional exponents to radicals */
{ term u,num,denom;
  if (FUNCTOR(t) != '^')
     return 1;
  u = ARG(1,t);
  if(FUNCTOR(u) != '/')
     return 1;
  num = ARG(0,u);
  denom = ARG(1,u);
  if((OBJECT(denom) && TYPE(denom) == BIGNUM)
     || (OBJECT(denom) && TYPE(denom) == INTEGER && INTDATA(denom) > 0xffff)
    )
     { errbuf(0, english(444));
          /* MathXpert can't cope with root(n,x) */
       errbuf(0, english(445));
          /* unless n < 65,537.   */
       return 1;
     }
  if(ISONE(num))
     { if(OBJECT(denom) && TYPE(denom)==INTEGER && INTDATA(denom)==2)
          { *next = make_sqrt(ARG(0,t));
            HIGHLIGHT(*next);
            strcpy(reason,"$a ^ � = �a$");
            release(arithmetic);
            return 0;
          }
       if( ! (OBJECT(denom) && TYPE(denom) == INTEGER) )
          return 1;
          /*  ROOT is used only with integer arguments */
       *next = make_root(denom,ARG(0,t));
       HIGHLIGHT(*next);
       strcpy(reason,"$a^(1/n)=��a$");
       release(arithmetic);
       return 0;
     }
     /* Now num is not one */
  if(OBJECT(denom) && TYPE(denom)==INTEGER && INTDATA(denom)==2)
     { *next = make_sqrt(make_power(ARG(0,t),num));
       HIGHLIGHT(*next);
       strcpy(reason,"$a^(b/2) = �(a^b)$");
       release(arithmetic);
       return 0;
     }
  if(! (OBJECT(denom) && TYPE(denom)==INTEGER))
     return 1;
  *next = make_root(denom,make_power(ARG(0,t),num));
  HIGHLIGHT(*next);
  strcpy(reason,"$a^(b/n)=��(a^b)$");
  release(arithmetic);   /* perhaps inhibited by factorbase */
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int zerobase(term t, term arg, term *next, char *reason)
/* 0^b = 0  if b > 0 */
{ int err;
  term power;
  if(FUNCTOR(t)!= '^')
     return 1;
  if(!ZERO(ARG(0,t)))
     return 1;
  power = ARG(1,t);
  if(contains(power,LIMIT))
     { errbuf(0, english(746));
       /* First evaluate the limit in the exponent to be sure that it is defined and positive. */
       return 1;
     }
  err = check(le(zero,power));
  if(err)
     { errbuf(0, english(447)); /* Exponent must be positive. */
       return 1;
     }
  *next = zero;
  HIGHLIGHT(*next);
  strcpy(reason,"0^b = 0 if $b > 0$");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int unitbase(term t, term arg, term *next, char *reason)
/*  1^b = 1 */
{ int err;
  if(FUNCTOR(t)!= '^')
     return 1;
  if(!ONE(ARG(0,t)))
     return 1;
  err = infer(domain(ARG(1,t)));
  if(err)
    { errbuf(0,  english(448)); /* Exponent not known to be defined */
      return 1;
    }
  *next = one;
  HIGHLIGHT(*next);
  strcpy(reason,"1^n = 1");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int reversecollectpowers(term t, term arg, term *next, char *reason)
/* a^(b+c) = a^b a^c */
/* In case a is 10 or eulere, and one of the powers is e^ln b,
inhibit(collectpowers).  It will be released when e^ln b => b */

{ term u,p,a;
  unsigned short n;
  int i;
  int flag = 0;;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(1,t);
  if(FUNCTOR(u) != '+')
     return 1;
  n = ARITY(u);
  a = ARG(0,t);
  if(equals(a,eulere))
     flag = 1;
  else if(equals(a,ten))
     flag = 2;
  *next = make_term('*',n);
  for(i=0;i<n;i++)
     { p = ARG(i,u);
       if(flag == 1 && contains_monomially(p,LN))
          { inhibit(collectpowers);
            break;
          }
       else if(flag == 2 && contains_monomially(p,LOG))
          { inhibit(collectpowers);
            break;
          }
     }
  for(i=0;i<n;i++)
     ARGREP(*next,i,make_power(a,ARG(i,u)));
  strcpy(reason,"a^(b+c) = a^b a^c");
  HIGHLIGHT(*next);
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int reversecollectpowers2(term t, term arg, term *next, char *reason)
/* a^(b-c) = a^b/a^c */
/* In case a is 10 or eulere, and one of the powers is e^ln b,
inhibit(collectpowers).  It will be released when e^ln b => b */

{ term u,p,a;
  unsigned short n,count;
  int i,k1,k2,negflag;
  term num,denom,numpower,denompower,temp;
  int flag = 0;;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(1,t);
  if(FUNCTOR(u) != '+')
     return 1;
  n = ARITY(u);
  a = ARG(0,t);
  if(equals(a,eulere))
     flag = 1;
  else if(equals(a,ten))
     flag = 2;
  count = 0;
  for(i=0;i<n;i++)
     { if(NEGATIVE(ARG(i,u)))
          { ++count;
            negflag = i;
          }
     }
  if(count == 0)
     return 1;
  if(flag)
     { for(i=0;i<n;i++)
          { p = ARG(i,u);
            if(NEGATIVE(p))
               p = ARG(0,p);
            if(flag == 1 && contains_monomially(p,LN))
               { inhibit(collectpowers);
                 break;
               }
            else if(flag == 2 && contains_monomially(p,LOG))
               { inhibit(collectpowers);
                 break;
               }
          }
     }
  if(count == n)
     { /* all terms in exponent are negative */
       return 1;
     }
  if(n == 2)
     { *next = make_fraction(make_power(a,ARG(negflag ? 0 : 1,u)),
                             make_power(a,ARG(0,ARG(negflag,u)))
                            );
       HIGHLIGHT(*next);
       strcpy(reason,"a^(b-c) = a^b/a^c");
       return 0;
     }
  if(count == 1)
     { denom = make_power(a,ARG(0,ARG(negflag,u)));
       numpower = make_term('*',(unsigned short)(n-1));
       for(i=0;i<n-1;i++)
          ARGREP(numpower,i,ARG(i<negflag ? i : i+1,u));
       num = make_power(a,numpower);
       *next = make_fraction(num,denom);
       HIGHLIGHT(*next);
       strcpy(reason,"a^(b-c) = a^b/a^c");
       return 0;
     }
  numpower = make_term('*',(unsigned short)(n-count));
  denompower = make_term('*',count);
  k1 = k2 = 0;
  for(i=0;i<n;i++)
     { p = ARG(i,u);
       if(NEGATIVE(p))
          { p = ARG(0,p);
            ARGREP(denompower,k2,p);
            ++k2;
          }
       else
          { ARGREP(numpower,k1,p);
            ++k1;
          }
     }
  if(k1 != n-count)
     assert(0);
  if(k2 != count)
     assert(0);
  if(k1 == 1)
     { temp = ARG(0,numpower);
       RELEASE(numpower);
       numpower = temp;
     }
  *next = make_fraction(make_power(a,numpower),make_power(a,denompower));
  HIGHLIGHT(*next);
  strcpy(reason,"a^(b-c) = a^b/a^c");
  return 0;
}

/*______________________________________________________________________*/
MEXPORT_ALGEBRA int powerofminusone(term t, term arg, term *next, char *reason)
/* (-1)� when n is a fraction */
/* Works also on a product containing a power of -1 */
{ term u,p,q,r;
  int i,j,err;
  unsigned short n;
  unsigned short path[3];
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '^' && NEGATIVE(ARG(0,u)) && ONE(ARG(0,ARG(0,u))))
                { err = powerofminusone(u,arg,&q,reason);
                  if(err)
                     continue;
                  path[0] = '*';
                  path[1] = (unsigned short)(i+1);
                  path[2] = 0;
                  if(n==2 && ONE(q))
                     { *next = ARG(i?0:1,t);
                       set_pathtail(path);
                       return 0;
                     }
                  if(ONE(q))
                     { *next = make_term('*',(unsigned short)(n-1));
                       for(j=0;j<n-1;j++)
                          { ARGREP(*next,j, ARG(j<i ? j : j+1,t));
                          }
                     }
                  if(status(powerofminusone) == LEARNING || !equals(q,minusone))
                     { *next = make_term('*',n);
                        for(j=0;j<n;j++)
                          { ARGREP(*next,j, j==i ? q : ARG(j,t));
                          }
                        set_pathtail(path);
                        return 0;
                     }
                  if(equals(q,minusone))
                     { if(n==2)
                         { tneg(ARG(i ? 0 : 1,t),next);
                           set_pathtail(path);
                           return 0;
                         }
                       r = make_term('*',(unsigned short)(n-1));
                       for(j=0;j<n-1;j++)
                          { ARGREP(r,j, ARG(j<i ? j : j+1,t));
                          }
                       tneg(r,next);
                       set_pathtail(path);
                       return 0;
                     }
                }
          }
       return 1;
     }
  if(FUNCTOR(t) != '^')
     return 1;
  if(!equals(ARG(0,t),minusone))
     return 1;
  u = ARG(1,t);
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(INTEGERP(u))
     { if(ISODD(u))
          { *next = minusone;
            HIGHLIGHT(*next);
            strcpy(reason, english(742));  /* (-1)� = -1 (odd n) */
            return 0;
          }
       else
          { *next = one;
            HIGHLIGHT(*next);
            strcpy(reason, english(743));  /*(-1)� = 1 (even n) */
            return 0;
          }
     }
  if(possible_int(u))
     return intpowerofminusone(t,arg,next,reason);

     /* possible_int's don't contain fractions, so can exit
        for good on possible_ints */

  if(!RATIONALP(u))
     return 1;
  p = ARG(0,u);
  q = ARG(1,u);
  gcd(p,q,&r);
  if(!ONE(r))
     { err = value(make_fraction(p,r),&p);
       assert(!err);
       err = value(make_fraction(q,r),&q);
       assert(!err);
     }
  if(ISEVEN(p) && !get_complex())
     { *next = one;
       HIGHLIGHT(*next);
       strcpy(reason,"(-1)^(p/q)=1 (p even)");
       return 0;
     }
  else if(!get_complex() && ISEVEN(q))
     { commentbuf(0, english(449));
            /* This power of -1 is undefined when working with */
       commentbuf(1, english(450));
           /*  real numbers only, as you are at the moment. */
       commentbuf(2, english(451));
           /* Try it again under Complex Numbers */
       return 1;
     }
  else if(!get_complex())
     { /* Now both p and q are odd */
       *next = minusone;
       HIGHLIGHT(*next);
       strcpy(reason, english(452));  /* (-1)^(odd/odd) = -1 */
       return 0;
     }
       /* from here on, complex numbers are on */
  else if(equals(q,two) && equals(p,one))  /* (-1)^(1/2) = i */
     { *next = complexi;
       HIGHLIGHT(*next);
       strcpy(reason, "$(-1)^� = i$");
       return 0;
     }
  else if(equals(q,two) && ISODD(p))   /* (-1)^(p/2) = �i */
     { /* Is (p-1)/2 even or odd ? */
       if(
          (ISINTEGER(p) && (INTDATA(p) & 2)) ||  /* (p-1)/2 is odd */
          (TYPE(p)==BIGNUM && (BIGNUMDATA(p).val[0] & 2))
         )
          { tneg(complexi,next);
            HIGHLIGHT(*next);
            strcpy(reason,"(-1)^(4k-1)/2 = -i");
            return 0;
          }
       else
          { *next = complexi;
            HIGHLIGHT(*next);
            strcpy(reason,"(-1)^(4k+1)/2 = i");
            return 0;
          }
     }
  else
     { *next = make_power(eulere,make_fraction(product3(pi,complexi,p),q));
       HIGHLIGHT(*next);
       strcpy(reason,"$(-1)^(p/q)=e^(�ip/q)$");
       return 0;
     }
}

/*______________________________________________________________________*/
MEXPORT_ALGEBRA int intpowerofminusone(term t, term arg, term *next, char *reason)
/* (-1)� when n is an integer */
/* Works also on a product containing a power of -1 */
{ term u,q,r;
  int i,j,err;
  unsigned short n;
  unsigned short path[3];
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '^' && NEGATIVE(ARG(0,u)) && ONE(ARG(0,ARG(0,u))))
                { err = intpowerofminusone(u,arg,&q,reason);
                  if(err)
                     continue;
                  path[0] = '*';
                  path[1] = (unsigned short)(i+1);
                  path[2] = 0;
                  set_pathtail(path);
                  if(n==2 && ONE(q))
                     { *next = ARG(i?0:1,t);
                       return 0;
                     }
                  if(ONE(q))
                     { *next = make_term('*',(unsigned short)(n-1));
                       for(j=0;j<n-1;j++)
                          { ARGREP(*next,j, ARG(j<i ? j : j+1,t));
                          }
                     }
                  if(status(intpowerofminusone) == LEARNING || !equals(q,minusone))
                     { *next = make_term('*',n);
                        for(j=0;j<n;j++)
                          { ARGREP(*next,j, j==i ? q : ARG(j,t));
                          }
                        return 0;
                     }
                  if(equals(q,minusone))
                     { if(n==2)
                         { tneg(ARG(i ? 0 : 1,t),next);
                           return 0;
                         }
                       r = make_term('*',(unsigned short)(n-1));
                       for(j=0;j<n-1;j++)
                          { ARGREP(r,j, ARG(j<i ? j : j+1,t));
                          }
                       tneg(r,next);
                       return 0;
                     }
                }
          }
       return 1;
     }
  if(FUNCTOR(t) != '^')
     return 1;
  if(!equals(ARG(0,t),minusone))
     return 1;
  u = ARG(1,t);
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(INTEGERP(u))
     { if(ISODD(u))
          { *next = minusone;
            HIGHLIGHT(*next);
            strcpy(reason, english(742)); /* (-1)� = -1 (odd n) */
            return 0;
          }
       else
          { *next = one;
            HIGHLIGHT(*next);
            strcpy(reason, english(743));  /* (-1)� = 1 (even n) */
            return 0;
          }
     }
  if(iseven(u))
     { *next = one;
       HIGHLIGHT(*next);
       strcpy(reason, english(743));
       return 0;
     }
  if(isodd(u))
     { *next = minusone;
       HIGHLIGHT(*next);
       strcpy(reason,english(742));
       return 0;
     }
  /* I doubt if there are any cases covered by the rest of the code that
     are not already trapped above.  But the following code has been there
     long before the above was added, so it shall remain just in case it
     is doing something useful. */
  if(possible_int(u) && !infer(type(u,INTEGER)))
     { err = infer(even(u));
       if(!err)
          { *next = one;
            HIGHLIGHT(*next);
            strcpy(reason, english(743));
            return 0;
          }
       err = infer(odd(u));
       if(!err)
          { *next = minusone;
            HIGHLIGHT(*next);
            strcpy(reason,english(742));
            return 0;
          }
      }
  return 1;
}

/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int poweroutoffraction(term t, term arg, term *next, char *reason)
/* a�/b� = (a/b)� */
/* Used only in solving equations. In automode must protect the
resulting power of a fraction, which is to be undone by taking the
root of both sides of an equation.  It works on an equation or inequality
as well as on a quotient, if the other side is constant,
and in automode is only called on equations.  */

{ term a,b,u,v,n;
  unsigned short f = FUNCTOR(t);
  unsigned short path[5];
  int problemtype = get_problemtype();
  if(f == '=' && SOLVETYPE(problemtype) && econstant(ARG(1,t)))
     { int err = poweroutoffraction(ARG(0,t),arg,&v,reason);
       if(err)
          return 1;
       PROTECT(v);
       *next = equation(v,ARG(1,t));
       path[0] = f;
       path[1] = 1;
       path[2] = 0;
       set_pathtail(path);
       return 0;
     }
  if((f == '<' || f ==LE) && SOLVETYPE(problemtype) && econstant(ARG(1,t)))
     { int err = poweroutoffraction(ARG(0,t),arg,&v,reason);
       if(err)
          return 1;
       PROTECT(v);
       *next = equation(v,ARG(1,t));
       path[0] = f;
       path[1] = 1;
       path[2] = 0;
       set_pathtail(path);
       return 0;
     }
  if((f == '<' || f ==LE) && SOLVETYPE(problemtype) && econstant(ARG(0,t)))
     { int err = poweroutoffraction(ARG(1,t),arg,&v,reason);
       if(err)
          return 1;
       PROTECT(v);
       *next = equation(ARG(0,t),v);
       path[0] = f;
       path[1] = 2;
       path[2] = 0;
       set_pathtail(path);
       return 0;
     }
  if(!FRACTION(t))
     return 1;
  u = ARG(0,t);
  v = ARG(1,t);
  if(FUNCTOR(u) != '^' || FUNCTOR(v) != '^')
     return 1;
  n = ARG(1,u);
  if(!equals(n,ARG(1,v)))
     return 1;
  a = ARG(0,u);
  b = ARG(0,v);
  *next = make_power(make_fraction(a,b),n);
  HIGHLIGHT(*next);
  strcpy(reason,"$a�/b� = (a/b)�$");
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int  eliminatenegexpnum(term t, term arg, term *next, char *reason)
/*      a^(-n)/b = 1/(a�b) */
{  /* take negative exponents out of the numerator and stick them
      in the denominator in correct multiplicative order */
   term u,num,den,denom,temp,top,bottom;
   int i,err,somethingdone = 0;
   unsigned short k,count;
   if(FUNCTOR(t) != '/')
      return 1;
   top = ARG(0,t);
   bottom = ARG(1,t);
   if(FUNCTOR(top) == '^')
      { err = negexp_aux(top,&u);
        if(err)
           return 1;
        mt(make_power(ARG(0,top),u),bottom,&denom);
        HIGHLIGHT(ARG(0,denom));
        if(FUNCTOR(denom)== '*')
           sortargs(denom);
        *next = make_fraction(one,denom);
        strcpy(reason,"$a^(-n) = 1/a�$");
        return 0;
      }
   else if(FUNCTOR(top) == '*')
      { num = make_term('*',ARITY(top));
        if(FUNCTOR(bottom)=='*')
           den = make_term('*',(unsigned short)(ARITY(top) + ARITY(bottom)));
        else
           den = make_term('*', (unsigned short)(ARITY(top) + 1));
        count = k = 0;
        for(i=0;i<ARITY(top);i++)
           { arg = ARG(i,top);
             err = negexp_aux(arg,&u);
             if(!err)
                { ARGREP(den,count,make_power(ARG(0,arg),u));
                  HIGHLIGHT(ARG(count,den));
                  ++count;
                  ++somethingdone;
                }
             else
                { ARGREP(num,k,arg);
                  ++k;
                }
           }
        SETFUNCTOR(num,'*',k);
        SETFUNCTOR(den,'*',count);
        if(count == 0 || somethingdone == 0)
           { RELEASE(num);
             RELEASE(den);
             return 1;
           }
        if(count==1)
           { temp = ARG(0,den);
             RELEASE(den);
             den = temp;
           }
        if(k==1)
           { temp = ARG(0,num);
             RELEASE(num);
             num = temp;
           }
        if(k==0)
           { RELEASE(num);
             num = one;
           }
        if(count >= 1)
           { mt(den,bottom,&denom);
             if(FUNCTOR(denom)=='*')
                sortargs(denom);
             *next = make_fraction(num,denom);
             strcpy(reason,"$a^(-n)/b = 1/(a�b)$");
             return 0;
           }
      }
  return 1;
}
/*____________________________________________________________________*/
static term powerstonum_aux(term u, term v)
/* u and v are a^n and a^m  (or just a); return a^(n-m), with
the exponent simplified. */
{ term a,n,m,newpower,ans;
  if(FUNCTOR(u) == '^')
     { a = ARG(0,u);
       n = ARG(1,u);
     }
  else
     { a = u;
       n = one;
     }
  if(FUNCTOR(v) == '^')
     { assert(equals(a,ARG(0,v)));
       m = ARG(1,v);
     }
  else
     { assert(equals(a,v));
       m = one;
     }
  polyval(sum(n,tnegate(m)),&newpower);
  ans = ZERO(newpower) ? one : make_power(a,newpower);
  HIGHLIGHT(ans);
  return ans;
}
/*____________________________________________________________________*/
#define BASE(p)  (FUNCTOR(p) == '^' ? ARG(0,p) : (p))
MEXPORT_ALGEBRA int powerstonum(term t, term arg, term *next, char *reason)
/* a^n/a^m = a^(n-m) */
/* Sometimes cancel will not do this job, e.g. a^(k-6)/a^(k/2)  */
/* Don't succeed if n==m */
{ int i,j,k;
  term num,denom,a,u,v,newnum,newdenom,w;
  unsigned short f,g,n,m;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  f = FUNCTOR(num);
  g = FUNCTOR(denom);
  /* First identify the base a to be used */
  if(f == '^' && g == '^')
     { if(!equals(ARG(0,denom),ARG(0,num)))
          return 1;
       *next = w = powerstonum_aux(num,denom);
       goto out;
     }
  if(f == '^' && ISATOM(denom) && equals(denom,ARG(0,num)))
     { *next = w = powerstonum_aux(num,denom);
       goto out;
     }
  else if(g == '^' && ISATOM(num) && equals(num,ARG(0,denom)))
     { *next = w = powerstonum_aux(num,denom);
       goto out;
     }
  else if((ISATOM(num) || f == '^') && g == '*')
     { u = num;
       a = BASE(num);
       m = ARITY(denom);
       for(j=0;j<m;j++)
          { v = ARG(j,denom);
            if(FUNCTOR(v) == '^' && equals(ARG(0,v),a))
                break;
            if(equals(v,a) && f == '^')
                break;
          }
       if(j==m)
          return 1;
       newnum = w = powerstonum_aux(u,v);
       if(m == 2)
          newdenom = ARG(j ? 0 : 1, denom);
       else
          { newdenom = make_term('*',(unsigned short)(m-1));
            for(k=0;k<m-1;k++)
               ARGREP(newdenom,k, ARG((k<j ? k : k+1),denom));
          }
       *next = make_fraction(newnum,newdenom);
       goto out;
     }
  else if((ISATOM(denom) || g == '^') && f == '*')
     { v = denom;
       a = BASE(denom);
       n = ARITY(num);
       for(i=0;i<n;i++)
          { u = ARG(i,num);
            if(FUNCTOR(u) == '^' && equals(ARG(0,u),a))
                break;
            if(equals(u,a) && g == '^')
                break;
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(k=0;k<n;k++)
          { if(k == i)
               { w = powerstonum_aux(u,v);
                 ARGREP(*next,k,w);
               }
            else
               ARGREP(*next,k,ARG(k,num));
          }
       goto out;
     }
  else if(f == '*' && g == '*')
     { n = ARITY(num);
       m = ARITY(denom);
       for(i=0;i<n;i++)
          { u = ARG(i,num);
            a = BASE(u);
            for(j=0;j<m;j++)
                { v = ARG(j,denom);
                  if(equals(BASE(v),a) && !(ISATOM(v) && ISATOM(v)))
                      break;
                }
            if(j < m)
               break;
          }
       if(i == n)
          return 1;
       if(equals(ARG(i,num),ARG(j,denom)))
          return 1;  /* don't just cancel */
       newnum = make_term('*',n);
       for(k=0;k<n;k++)
          { if(i==k)
               { w = powerstonum_aux(u,v);
                 ARGREP(newnum,k,w);
               }
            else
               ARGREP(newnum,k,ARG(k,num));
          }
       if(m==2)
          newdenom = ARG(j ? 0 : 1, denom);
       else
          { newdenom = make_term('*',(unsigned short)(m-1));
            for(k=0;k<m-1;k++)
               ARGREP(newdenom,k, ARG((k<j ? k : k+1),denom));
          }
       *next = make_fraction(newnum,newdenom);
       goto out;
     }
  else
     return 1;
  out:
    /* Don't create negative exponents in automode unless negexpflag says to */
    if( FUNCTOR(w) == '^' && NEGATIVE(ARG(1,w)) &&
        get_mathmode() == AUTOMODE &&
        get_polyvalnegexpflag() != -1
      )
        return 1;
    strcpy(reason,"a^n/a^m = a^(n-m)");
    return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int powerstodenom(term t, term arg, term *next, char *reason)
/* ab^n/b^m = a/b^(m-n) */
{ int err;
  term u;
  if(FUNCTOR(t) != '/')
     return 1;
  err = powerstonum(reciprocal(t),arg,&u,reason);
  if(err)
     return 1;
  *next = reciprocal(u);
  strcpy(reason,"ab^n/b^m = a/b^(m-n)");
  return 0;
}
/*______________________________________________________________________*/
MEXPORT_ALGEBRA int possible_int(term t)
/* Return 1 if t is an INTEGERP or an mvpoly in variables of type
INTEGER.  Return 0 otherwise. */
{ unsigned short n,f;
  int i;
  if(INTEGERP(t))
     return 1;
  if(ISATOM(t) && TYPE(t) == INTEGER)
     return 1;
  if(ATOMIC(t))
     return 0;  /* otherwise */
  n = ARITY(t);
  f = FUNCTOR(t);
  if(f == '-')
     return possible_int(ARG(0,t));
  if(f != '^' && f != '+' && f != '*')
     return 0;
  for(i=0;i<n;i++)
     { if(!possible_int(ARG(i,t)))
           return 0;
     }
  return 1;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int expandsquare(term t, term arg, term *next, char *reason)
/* a^2 = aa */
{ term a;
  if(FUNCTOR(t)!= '^')
     return 1;
  if(!equals(ARG(1,t),two))
     return 1;
  a = ARG(0,t);
  *next = make_term('*',2);
  ARGREP(*next,0,a);
  ARGREP(*next,1,a);
  HIGHLIGHT(*next);
  strcpy(reason,"a^2 = aa");
  return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int expandcube(term t, term arg, term *next, char *reason)
/* a^3 = aaa*/
{ term a;
  if(FUNCTOR(t)!= '^')
     return 1;
  if(!equals(ARG(1,t),three))
     return 1;
  a = ARG(0,t);
  *next = make_term('*',3);
  ARGREP(*next,0,a);
  ARGREP(*next,1,a);
  ARGREP(*next,2,a);
  HIGHLIGHT(*next);
  strcpy(reason,"a^3 = aaa");
  return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int expandpower(term t, term arg, term *next, char *reason)
/* a^n = aaa...(n times) */
{ term a;
  long n;
  int i;
  if(FUNCTOR(t)!= '^')
     return 1;
  if(!ISINTEGER(ARG(1,t)))
     return 1;
  n = INTDATA(ARG(1,t));
  if(n > 100)
     { errbuf(0, english(1591));  /* exponent cannot exceed 100 */
       return 1;
     }
  a = ARG(0,t);
  *next = make_term('*',(unsigned short) n);
  for(i=0;i<n;i++)
    ARGREP(*next,i,a);
  HIGHLIGHT(*next);
  strcpy(reason,"a^n = aaa...(n times)");
  return 0;
}

/*_______________________________________________________________________*/
MEXPORT_ALGEBRA int cleanupexponents(term t, term arg, term *next, char *reason)
/* if a factor of t has a numerical sum in the exponent,
evaluate that sum.  Evaluate only the first such sum, so the
effect of this automode_only operator can be imitated using 'arithmetic'.
*/

{ unsigned short n;
  term u,v,base,power;
  int i,j;
  unsigned short path[5];
  if(FUNCTOR(t) != '*')
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) != '^')
          continue;
       base = ARG(0,u);
       power = ARG(1,u);
       if(FUNCTOR(power) == '+' && numerical(power))
          { value(power,&v);
            if(!equals(v,power))
               { HIGHLIGHT(v);
                 u = make_power(base,v);
                 *next = make_term('*',n);
                 for(j=0;j<n;j++)
                    ARGREP(*next,j,j==i ? u : ARG(j,t));
                 strcpy(reason, english(417));  /* arithmetic */
                 path[0] = '*';
                 path[1] = (unsigned short)(i+1);
                 path[2] = '^';
                 path[3] = 2;
                 path[4] = 0;
                 set_pathtail(path);
                 SetShowStepOperation(arithmetic);
                 return 0;
               }
          }
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int eliminateconstnegexpnum(term t, term arg, term *next, char *reason)
/*      a^(-n)/b = 1/(a�b) (n constant )*/
{  /* take negative exponents out of the numerator and stick them
      in the denominator in correct multiplicative order */
   term u,num,den,denom,temp,top,bottom;
   int i,err,somethingdone = 0;
   unsigned short k,count;
   if(FUNCTOR(t) != '/')
      return 1;
   top = ARG(0,t);
   bottom = ARG(1,t);
   if(FUNCTOR(top) == '^' && !constant(ARG(1,top)))
      return 1;
   if(FUNCTOR(top) == '^')
      { err = negexp_aux(top,&u);
        if(err)
           return 1;
        mt(make_power(ARG(0,top),u),bottom,&denom);
        HIGHLIGHT(ARG(0,denom));
        if(FUNCTOR(denom)== '*')
           sortargs(denom);
        *next = make_fraction(one,denom);
        strcpy(reason,"$a^(-n) = 1/a�$");
        goto success;
      }
   if(FUNCTOR(top) == '*')
      { num = make_term('*',ARITY(top));
        if(FUNCTOR(bottom)=='*')
           den = make_term('*',(unsigned short)(ARITY(top) + ARITY(bottom)));
        else
           den = make_term('*', (unsigned short)(ARITY(top) + 1));
        count = 0;
        k = 0;
        for(i=0;i<ARITY(top);i++)
           { arg = ARG(i,top);
             if( FUNCTOR(arg) == '^' && !constant(ARG(1,arg)))
                { ARGREP(num,k,arg);
                  ++k;
                  continue;
                }
             err = negexp_aux(arg,&u);
             if(!err)
                { ARGREP(den,count,make_power(ARG(0,arg),u));
                  HIGHLIGHT(ARG(count,den));
                  ++count;
                  ++somethingdone;
                }
             else
                { ARGREP(num,k,arg);
                  ++k;
                }
           }
        SETFUNCTOR(num,'*',k);
        SETFUNCTOR(den,'*',count);
        if(count == 0 || somethingdone == 0)
           { RELEASE(num);
             RELEASE(den);
             return 1;
           }
        if(count==1)
           { temp = ARG(0,den);
             RELEASE(den);
             den = temp;
           }
        if(k==1)
           { temp = ARG(0,num);
             RELEASE(num);
             num = temp;
           }
        if(k==0)
           { RELEASE(num);
             num = one;
           }
        if(count >= 1)
           { mt(den,bottom,&denom);
             if(FUNCTOR(denom)=='*')
                sortargs(denom);
             *next = make_fraction(num,denom);
             strcpy(reason,"$a^(-n)/b = 1/(a�b)$");
             goto success;
           }
      }
  return 1;
  success:
     return 0;
}
#if 0
/*___________________________________________________________________*/
static int contains_varnegexp(term t)
/* return 1 if t contains a non-constant negative exponent */
/* Does not look for nested exponents */
{ int i;
  unsigned short n;
  unsigned short f = FUNCTOR(t);
  if(ATOMIC(t))
     return 0;
  if(f == '^' && NEGATIVE(ARG(1,t)) && !seminumerical(ARG(0,ARG(1,t))))
     { if(contains(t,INFINITY))
         { term *atomlist;
           int nvars = variablesin(t,&atomlist);
           free2(atomlist);
           if(nvars != 0)
              return 1;
           else
              return contains_varnegexp(ARG(0,t));
         }
      return 1;
    }
  if(f == '^')
     return contains_varnegexp(ARG(0,t));
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_varnegexp(ARG(i,t)))
          return 1;
     }
  return 0;
}
#endif
/*_______________________________________________________________*/
MEXPORT_ALGEBRA int fractexpdenom(term t, term arg, term *next, char *reason)
/*  a/b^(p/q) = (a^q/b^p)^(1/q) */
{ term a,b,p,q,qq;
  int err;
  if(!FRACTION(t))
     return 1;
  if(FUNCTOR(ARG(1,t)) != '^')
     return 1;
  if(!FRACTION(ARG(1,ARG(1,t))))
     return 1;
  a = ARG(0,t);
  b = ARG(0,ARG(1,t));
  p = ARG(0,ARG(1,ARG(1,t)));
  q = ARG(1,ARG(1,ARG(1,t)));
  if(!isodd(q) && !obviously_nonnegative(a))
     { err = infer(le(zero,a));
       if(err)
          { errbuf(0, english(1915));
            /* Numerator must be non-negative */
            return 1;
          }
     }
  copy(reciprocal(q),&qq);
  *next = make_power(make_fraction(make_power(a,q),make_power(b,p)),qq);
  HIGHLIGHT(*next);
  strcpy(reason,"a/b^(p/q) = (a^q/b^p)^(1/q)");
  return 0;
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int fractexpnum(term t, term arg, term *next, char *reason)
/* a^(p/q)/b = (a^p/b^q)^1/q)  */
{ term a,b,p,q,qq;
  int err;
  if(!FRACTION(t))
     return 1;
  if(FUNCTOR(ARG(0,t)) != '^')
     return 1;
  if(!FRACTION(ARG(1,ARG(0,t))))
     return 1;
  b = ARG(1,t);
  a = ARG(0,ARG(0,t));
  p = ARG(0,ARG(1,ARG(0,t)));
  q = ARG(1,ARG(1,ARG(0,t)));
  if(!isodd(q) && !obviously_nonnegative(b))
     { err = infer(le(zero,b));
       if(err)
          { errbuf(0, english(1916));
            /* Denominator must be non-negative */
            return 1;
          }
     }
  copy(reciprocal(q),&qq);
  *next = make_power(make_fraction(make_power(a,p),make_power(b,q)),qq);
  HIGHLIGHT(*next);
  strcpy(reason,"a^(p/q)/b = (a^p/b^q)^1/q)");
  return 0;
}

/*_____________________________________________________________*/
MEXPORT_ALGEBRA int breakpower(term t, term arg, term *next, char *reason)
/* x^n = x^? x^(n-?)  on the menus */
{ term n,b,x;
  if(FUNCTOR(t) != '^')
     return 1;
  n = ARG(1,t);
  polyval(sum(n,tnegate(arg)),&b);
  copy(ARG(0,t),&x);
  *next = product(make_power(x,arg),make_power(ARG(0,t),b));
  HIGHLIGHT(*next);
  strcpy(reason,"x^n = x^m x^(n-m)");
  return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int reversepowertopower1(term t, term arg, term *next, char *reason)
/* a^(bc) = (a^b)^c  if a>0 or c�Z */

{ term n,a,b,c;
  if(FUNCTOR(t) != '^')
     return 1;
  n = ARG(1,t);
  if(FUNCTOR(n) != '*')
     return 1;
  a = ARG(0,t);
  b = ARG(0,n);
  if(ARITY(n) != 2)
     return 1;
  c = ARG(1,n);
  if(isinteger(c) || obviously_positive(a))
     { *next = make_power(make_power(a,b),c);
       HIGHLIGHT(*next);
       strcpy(reason,"a^(bc) = (a^b)^c");
       return 0;
     }
  return 1;
}

/*____________________________________________________________________*/
MEXPORT_ALGEBRA int reversepowertopower2(term t, term arg, term *next, char *reason)
/* a^(bc) = (a^c)^b  if a>0 or c�Z */
{ term n,a,b,c;
  if(FUNCTOR(t) != '^')
     return 1;
  n = ARG(1,t);
  if(FUNCTOR(n) != '*')
     return 1;
  a = ARG(0,t);
  b = ARG(0,n);
  if(ARITY(n) != 2)
     return 1;
  c = ARG(1,n);
  if(isinteger(b) || obviously_positive(a))
     { *next = make_power(make_power(a,c),b);
       HIGHLIGHT(*next);
       strcpy(reason,"a^(bc) = (a^c)^b");
       return 0;
     }
  return 1;
}

/*____________________________________________________________________*/
MEXPORT_ALGEBRA int reversepowertopower3(term t, term arg, term *next, char *reason)
/* a^(b?) = (a^b)^?  (available with products of 3 or more terms in the exponent) */
{ term n,a,b,c;
  if(FUNCTOR(t) != '^')
     return 1;
  n = ARG(1,t);
  if(FUNCTOR(n) != '*')
     return 1;
  if(ARITY(n) <= 2)
     return 1;
  if(FUNCTOR(arg) == ILLEGAL)
     return 1;
  if(cancel(n,arg,&b,&c)  || !equals(c,arg))
     return 1;
  a = ARG(0,t);
  if(isinteger(c) || obviously_positive(a))
     { *next = make_power(make_power(a,b),c);
       strcpy(reason,"a^(bc) = (a^c)^b");
       HIGHLIGHT(*next);
       return 0;
     }
  return 1;
}

/*____________________________________________________________________*/
MEXPORT_ALGEBRA int poweroutofrecip(term t, term arg, term *next, char *reason)
/* 1/a^n = (1/a)^n */
{ if(!FRACTION(t))
     return 1;
  if(!ONE(ARG(0,t)))
     return 1;
  if(FUNCTOR(ARG(1,t)) != '^')
     return 1;
  *next = make_power(reciprocal(ARG(0,ARG(1,t))),ARG(1,ARG(1,t)));
  strcpy(reason,"1/a^n = (1/a)^n");
  HIGHLIGHT(*next);
  return 0;
}

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