Sindbad~EG File Manager

Current Path : /usr/home/beeson/Otter-Lambda/yyy/trigcalc/
Upload File :
Current File : /usr/home/beeson/Otter-Lambda/yyy/trigcalc/inflims.c

/*  operators for infinite limits and limits at infinity, for MathXpert */
/* M. Beeson
1.15.92 Original date
10.21.99 modified
1.4.00  corrected addinfinity
4.18.00  corrected sumleadingterm, adding if(!ZERO(a)) x = sum(x,tnegate(a)); in two places
4.21.00  removed superfluous variables from use_comdenom_instead
4.21.00  corrected the 4.18 correction
1.29.06  rewrote use_comdenom_instead. 
*/

/* Note: � is used for the limit arrow in reason strings, since
the OEM font limit arrow is also the end-of-file character.
SymbolTextOut prints it correctly. */

#include <string.h>
#include <assert.h>
#include <math.h>
#define TRIGCALC_DLL
#include "globals.h"
#include "ops.h"
#include "calc.h"
#include "prover.h"
#include "order.h"
#include "sqrts.h"   /* grf_aux */
#include "mplimits.h"
#include "symbols.h"
#include "mathmode.h"  /* get_mathmode */
#include "errbuf.h"
#include "binders.h"  /* get_limit_info */
#include "pvalaux.h"  /* isodd          */
#include "autosimp.h" /* SetShowStepOperation */
#include "pathtail.h"
#include "algaux.h"   /* path_to_difference */
#include "dispfunc.h" /* functor_string     */
#include "probtype.h"
#include "loglead.h"  /* log_leading_term   */
#include "polynoms.h" /* ispolyin           */

static int limunary_aux(unsigned short g, term t, term *next, char *reason);

/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limquoinfinite(term t, term arg, term *next, char *reason)
/* lim u/v when lim v = 0, lim u !=0 */
/* works only when limval can get the limits of num or denom */
/* watch out for things like lim(x->0, 1/(x sin^2 x)) which
   fails to exist because the denominator isn't defined in a nbhd */

{ int err;
  term num,den;
  term w,u,v;  /* t = lim(x->a,u/v)  or lim(x->a,dir,u/v)  */
  if(FUNCTOR(t) != LIMIT)
     return 1;
  w = LIMITAND(t);
  if(FUNCTOR(w) != '/')
     return 1;
  u = ARG(0,w);
  if(OBJECT(u))
     { num = u;
       err = 0;
     }
  else if(ARITY(t)==2)
     err = limval(limit(ARG(0,t),u),&num);
  else
     err = limval(limit3(ARG(0,t),ARG(1,t),u),&num);
  if(err)
     { errbuf(0, english(951));
          /* Can't calculate limit of numerator */
       return 1;
     }
  if(equals(num,zero))
     { errbuf(0, english(838)); /* Limit of numerator is zero. */
       return 1;
     }
  v = ARG(1,w);
  if(ARITY(t)==2)
     err = limval(limit(ARG(0,t),v),&den);
  else
     err = limval(limit3(ARG(0,t),ARG(1,t),v),&den);
  if(err)
     { errbuf(0, english(947));
          /* Can't calculate limit of denominator. */
       return 1;
     }
  if(!equals(den,zero))
      { errbuf(0, english(839));
           /* Limit of denominator is not zero. */
        return 1;
      }
  err = limval(t,next);  /* wastefully duplicates the computation above,
           but we need to know if the limit is infinity,
           minusinfinity, undefined or unbounded_oscillations */
  assert(!err);  /* we can calculate the limit of numerator and denom
                    so at worst we will get undefined */
  HIGHLIGHT(*next);
  if(OBJECT(num))
     strcpy(reason, equals(*next,infinity) ? english(945) :
                    equals(*next,minusinfinity) ? english(946) :
                    english(947));
     /* 1/u�� if u>0 and u�\60
        1/u�-� if u<0 and u�\60
        lim 1/u  undefined    if lim u=0  */
  else if(equals(*next,infinity))
     strcpy(reason,english(949));
        /*  u/v�� if v lim u > 0   and v�\60  */
  else if(equals(*next,minusinfinity))
     strcpy(reason,english(950));
        /* u/v�-� if v lim u < 0  and u�\60   */
  else
     strcpy(reason, english(841));
     /* lim u/v undefined    if v�\60 and not u�\60 */
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_TRIGCALC int inflimpower1(term t, term arg, term *next, char *reason)
/*  1/x� -> 0 as x->� (n>0) */
/*   Also works on x^(-n) */
{ term u,x,a,n,c,s;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  a = ARG(1,ARG(0,t));
  if(!equals(a,infinity) && !equals(a,minusinfinity))
     return 1;
  assert(ARITY(t)==2);  /* limits at infinity are never one-sided */
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  if(FUNCTOR(u) == '^' && equals(ARG(0,u),x))
     { err = infer(lessthan(ARG(1,u),zero));
       if(err)
          return 1;
       goto out;
     }
  if(FUNCTOR(u) != '/')
     return 1;
  if(depends(ARG(0,u),x))
     return 1;
  ncs(ARG(1,u),&n,&c,&s);
  if(equals(s,x))
     goto out;
  if(FUNCTOR(s) == '^' && equals(ARG(0,s),x))
     { err = infer(positive(ARG(1,s)));
       if(!err)
          goto out;
       errbuf(0, english(842));
          /* Exponent in denominator must be positive */
       return 1;
     }
  return 1;
  out:
  *next = zero;
  HIGHLIGHT(*next);
  if(equals(a,infinity))
     strcpy(reason, english(959)); /* 1/x��\60 as x�� (n>0) */
  else /* a is minusinfinity */
     strcpy(reason, english(960));  /* 1/x��\60 as x�-� (n>0) */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_TRIGCALC int inflimpower2(term t, term arg, term *next, char *reason)
/*  lim(x��,x�) = � if n�1 */
{ term u,x,a;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  a = ARG(1,ARG(0,t));
  if(!equals(a,infinity) && !equals(a,minusinfinity))
     return 1;
  assert(ARITY(t)==2);  /* limits at infinity are never one-sided */
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  if(equals(u,x))
     { *next = equals(a,infinity) ? infinity : minusinfinity;
       if(equals(a,infinity))
          { strcpy(reason, "$lim (x��,x) = �$");
            *next = infinity;
          }
       else
          { strcpy(reason, "$lim (x�-�,x) = -�$");
            *next = minusinfinity;
          }
       HIGHLIGHT(*next);
       return 0;
     }
  if(FUNCTOR(u) != '^')
     return 1;
  if(!equals(ARG(0,u),x))
     return 1;
  err = infer(positive(ARG(1,u)));
  if(err)
     { errbuf(0, english(843));
          /* Exponent must be positive */
       return 1;
     }
  if(equals(a,infinity))
     { *next = infinity;
       HIGHLIGHT(*next);
       strcpy(reason, english(961));  /* x��� as x�� (n>0) */
       return 0;
     }
  err = infer(even(ARG(1,u)));
  if(!err)
     { strcpy(reason, english(962));  /* x^2��� as x�-� (n>0) */
       *next = infinity;
       HIGHLIGHT(*next);
       return 0;
     }
  err =infer(odd(ARG(1,u)));
  if(!err)
     { strcpy(reason, english(963)); /* x��-� as x�-�        */
       strcat(reason, english(952)); /* (n odd and positive) */
       *next = minusinfinity;
       HIGHLIGHT(*next);
       return 0;
     }
  *next = undefined;
  HIGHLIGHT(*next);
  errbuf(0, english(953));
    /* Can't determine the sign of the exponent */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_TRIGCALC int invertlim(term t, term arg, term *next, char *reason)
/* lim(x->�,f(x)) = lim(x->0+,f(1/x)) */
{ term u,x,v,a,dir;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  a = ARG(1,ARG(0,t));
  if(!equals(a,infinity) && !equals(a,minusinfinity))
     return 1;
  assert(ARITY(t)==2);  /* limits at infinity are never one-sided */
  u = LIMITAND(t);
  if(contains(u,DIFF))
     { errbuf(0, english(1410));
       /* You must first evaluate the derivative or derivatives */
       return 1;
     }
  x = ARG(0,ARG(0,t));
  subst(make_fraction(one,x),x,u,&v);
  dir = equals(a,infinity) ? right : left;
  *next = limit3(arrow(x,zero),dir,v);
  HIGHLIGHT(*next);
  if(equals(a,infinity))
     strcpy(reason, "$lim(x��,f(x))$ =       $lim(x�\60+,f(1/x))$");
  else
     strcpy(reason, "$lim(x�-�,f(x))$ =      $lim(x�\60-,f(1/x))$");
  return 0;
}
/*__________________________________________________________*/
MEXPORT_TRIGCALC int liminverseevenpower(term t, term arg, term *next, char *reason)
/* lim (1/u^2�) = � if u->0 */
{ term u,v,x;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  if(ARITY(t) != 2)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  if(FUNCTOR(u) != '/')
     return 1;
  if(depends(ARG(0,u),x))
     return 1;
  v = ARG(1,u);
  if(FUNCTOR(v) != '^')
     return 1;
  err = infer(even(ARG(1,v)));
  if(err)
     return 1;
  err = limquoinfinite(t,arg,next,reason);
  if(err)
     return 1;
  strcpy(reason, english(964));  /* lim (1/u^2�)=� if u�\60 */
  return 0;
}
/*__________________________________________________________*/
MEXPORT_TRIGCALC int liminverseoddpower(term t, term arg, term *next, char *reason)
/* lim(1/u�) undefined      if u->0, n odd */
{ term u,v,x;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  if(ARITY(t)!= 2)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  if(FUNCTOR(u) != '/')
     return 1;
  if(depends(ARG(0,u),x))
     return 1;
  v = ARG(1,u);
  if(FUNCTOR(v) != '^')
     return 1;
  err = infer(odd(ARG(1,v)));
  if(err)
     return 1;
  err = limquoinfinite(t,arg,next,reason);
  if(err)
     return 1;
  strcpy(reason, english(844));
     /* lim(1/u�) undefined      if u�\60, n odd */
  return 0;
}

/*__________________________________________________________*/
MEXPORT_TRIGCALC int lim1inverseleft(term t, term arg, term *next, char *reason)
/* lim(x->a-,1/u�)=-�, u->0, n odd */
{ term u,v,x;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  if(ARITY(t)!= 3)
     return 1;
  if(FUNCTOR(ARG(1,t)) != LEFT)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  if(FUNCTOR(u) != '/')
     return 1;
  if(depends(ARG(0,u),x))
     return 1;
  v = ARG(1,u);
  if(FUNCTOR(v) != '^')
     return 1;
  err = limquoinfinite(t,arg,next,reason);
  if(err)
     return 1;
  strcpy(reason, english(844));
      /* lim(1/u�) undefined      if u�\60, n odd */
  return 0;
}
/*__________________________________________________________*/
MEXPORT_TRIGCALC int lim1inverseright(term t, term arg, term *next, char *reason)
/*  lim(x->a+,1/u�) = � if u->0 */
{ term u,v,x;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  if(ARITY(t)!= 3)
     return 1;
  if(FUNCTOR(ARG(1,t)) != RIGHT)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  if(FUNCTOR(u) != '/')
     return 1;
  if(depends(ARG(0,u),x))
     return 1;
  v = ARG(1,u);
  if(FUNCTOR(v) != '^')
     return 1;
  err = limquoinfinite(t,arg,next,reason);
  if(err)
     return 1;
  strcpy(reason, english(844));
      /* lim(1/u�) undefined      if u�\60, n odd */
  return 0;
}

/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limlnsing(term t, term arg, term *next, char *reason)
/* limit of ln at zero */
{ term u,v,mid,ans;
  int err;
  if(FUNCTOR(t)!= LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != LN)
     return 1;
  v = ARG(0,u);
  mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
  err = limval(mid,&ans);
  if(err)
     return 1;
  if(!ZERO(ans))
     return 1;
  *next = minusinfinity;
  HIGHLIGHT(*next);
  strcpy(reason,"$lim(x�\60,ln x) = -�$");
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limtansing(term t, term arg, term *next, char *reason)
/* limit of tan at a singularity */
/* lim(x->(2n+1)�/2�,tan x) = �� but with signs switched */
{ int err;
  term a,x,u,v;
  unsigned short n;
  if(FUNCTOR(t)!=LIMIT)
     return 1;
  a = ARG(1,ARG(0,t));
  x = ARG(0,ARG(0,t));
  u = LIMITAND(t);
  n = ARITY(t);
  if(FUNCTOR(u) != TAN)
     return 1;
  if(!equals(x,ARG(0,u)))
     return 1;
  /* Now determine if a is an odd multiple of pi/2 */
  polyval(make_fraction(product(two,a),pi),&v);
  err = infer(odd(v));
  if(err)
     { errbuf(0, english(845));
          /*  Can't check limit is at an odd multiple of �/2. */
       return 1;
     }
  if(n==2)
     { *next = undefined;
       commentbuf(0, english(846));
           /* The one-sided limits have different signs. */
     }
  else if(equals(ARG(1,t),left))
     *next = infinity;
  else
     *next = minusinfinity;
  HIGHLIGHT(*next);
  strcpy(reason,"$$lim(x->(2n+1)pi/2");
  if(equals(ARG(1,t),left))
      strcat(reason,"-,     tan x) = infinity$$");
  else if(equals(ARG(1,t),right))
      strcat(reason,"+,     tan x) = -infinity$$");
  else
      strcat(reason,"       tan x) = undefined$$");
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limcotsing(term t, term arg, term *next, char *reason)
/* limit of cot at a singularity */
/*  lim(x->n��,cot x) = ��  */
{ int err;
  term a,x,u,v;
  unsigned short n;
  if(FUNCTOR(t)!=LIMIT)
     return 1;
  a = ARG(1,ARG(0,t));
  x = ARG(0,ARG(0,t));
  u = LIMITAND(t);
  n = ARITY(t);
  if(FUNCTOR(u) != COT)
     return 1;
  if(!equals(x,ARG(0,u)))
     return 1;
  /* Now determine if a is a multiple of pi */
  polyval(make_fraction(a,pi),&v);
  err = infer(type(v,INTEGER));
  if(err)
     { errbuf(0, english(847));
          /* Can't check limit is at a multiple of � */
       return 1;
     }
  if(n==2)
     { *next = undefined;
       commentbuf(0, english(846));
          /* The one-sided limits have different signs. */
       strcpy(reason,"$$lim(x-> n pi,cot x)=undefined$$");
     }
  else if(equals(ARG(1,t),left))
     { *next = minusinfinity;
       strcpy(reason,"$$lim(x-> n pi-,cot x)=-infinity$$");
     }
  else
     { *next = infinity;
       strcpy(reason,"$$lim(x-> n pi+,cot x)= infinity$$");
     }
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limcscsing(term t, term arg, term *next, char *reason)
/* limit of csc at a singularity */
/*  "lim(x->n��,csc x) = �� */
/*   The limit depends on the direction and on whether n is odd or even */
{ int err;
  term a,x,u,v;
  unsigned short n;
  if(FUNCTOR(t)!=LIMIT)
     return 1;
  a = ARG(1,ARG(0,t));
  x = ARG(0,ARG(0,t));
  u = LIMITAND(t);
  n = ARITY(t);
  if(FUNCTOR(u) != CSC)
     return 1;
  if(!equals(x,ARG(0,u)))
     return 1;
  /* Now determine if a is a multiple of pi */
  polyval(make_fraction(a,pi),&v);
  err = infer(type(v,INTEGER));
  if(err)
     { errbuf(0, english(847));
         /* Can't check limit is at a multiple of � */
       return 1;
     }
  if(n==2)
     { *next = undefined;
       commentbuf(0, english(846));
          /* The one-sided limits have different signs. */
       HIGHLIGHT(*next);
       strcpy(reason,"$$lim(x->n pi,csc x) = undefined$$");
     }
  /* Now we must determine if v is odd or even */
  if(iseven(v))
     { /* v is even , so a == 0 mod 2� */
       if(equals(ARG(1,t),left))
          { *next = minusinfinity;
            strcpy(reason,"$$lim(x-> 0-,csc x) = -infinity$$");
            HIGHLIGHT(*next);
            return 0;
          }
       else  /* limit from right at 0 */
          { *next = infinity;
            HIGHLIGHT(*next);
            strcpy(reason,"$$lim(x-> 0+,csc x) = infinity$$");
            return 0;
          }
     }
  /* Now v is not even */
  if(isodd(v))
     { if(equals(ARG(1,t),left))
          { *next = infinity;
            strcpy(reason,"$$lim(x-> pi-,csc x) = infinity$$");
            HIGHLIGHT(*next);
            return 0;
          }
       else  /* limit from the right */
          { *next = minusinfinity;
            strcpy(reason,"$$lim(x->pi+,csc x) = -infinity$$");
            HIGHLIGHT(*next);
            return 0;
          }
     }
  /* can't determine if it's odd or even */
  *next = undefined;
  strcpy(reason,"$$lim(x->n pi,csc x)= undefined$$");
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limsecsing(term t, term arg, term *next, char *reason)
/* limit of sec at a singularity */
/* lim(x->(2n+1)�/2�,sec x) = �� */
{ int err;
  term a,x,u,v;
  unsigned short n;
  if(FUNCTOR(t)!=LIMIT)
     return 1;
  a = ARG(1,ARG(0,t));
  x = ARG(0,ARG(0,t));
  u = LIMITAND(t);
  n = ARITY(t);
  if(FUNCTOR(u) != SEC)
     return 1;
  if(!equals(x,ARG(0,u)))
     return 1;
  /* Now determine if a is an odd multiple of pi/2 */
  polyval( sum(make_fraction(a,pi),tnegate(make_fraction(one,two))),&v);
  err = infer(type(v,INTEGER));
  if(err)
     { errbuf(0, english(848));
          /* Can't check limit is at an odd multiple of �/2 */
       return 1;
     }
  if(n==2)
     { *next = undefined;
       commentbuf(0, english(846));
          /*  The one-sided limits have different signs. */
       HIGHLIGHT(*next);
       strcpy(reason, "$$lim(x->(2n+1)pi/2, sec x) = undefined$$");
       return 0;
     }
  /* Now we have a one-sided limit to deal with.  We must know
  whether v is odd or even.  */
  if(iseven(v))
     { /* Now v is even where a = (2v+1)�/2 so a = �/2 mod 2� */
       if(equals(ARG(1,t),left))
          { *next = minusinfinity;
            strcpy(reason,"$$lim(x-> pi/2-, sec x) = -infinity$$");
            HIGHLIGHT(*next);
            return 0;
          }
       else   /*  if(equals(ARG(1,t),right)) */
          { *next = infinity;
            strcpy(reason, "$$lim(x-> pi/2+, sec x) = infinity$$");
            HIGHLIGHT(*next);
            return 0;
          }
     }
  if(isodd(v))
     /* Now v is odd, where a = (2v+1)�/2, so a = -�/2 mod 2� */
     { if(equals(ARG(1,t),left))
          { *next = minusinfinity;
            strcpy(reason,"$$lim(x-> -pi/2-, sec x) =-infinity$$");
            HIGHLIGHT(*next);
            return 0;
          }
       else
          { *next = infinity;
            strcpy(reason,"$$lim(x-> -pi/2+, sec x) = infinity$$");
            HIGHLIGHT(*next);
            return 0;
          }
     }
  /* can't determine whether v is odd or even */
  *next = undefined;
  commentbuf(0, english(1100));
  /* Limit has different signs at ��/2 */
  HIGHLIGHT(*next);
  strcpy(reason,english(1099));  /* see above */
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limexpinf(term t, term arg, term *next, char *reason)
/*  lim(x->�,e^x) = � */
{ term u,v,mid,ans;
  int err;
  if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= '^')
     return 1;
  if(FUNCTOR(t)=='^')
     { if(!equals(ARG(0,t),eulere))
           return 1;
       u = ARG(1,t);
       if(!NOTDEFINED(u))
           return 1;
       *next = u;
       if(equals(u,infinity))
          { strcpy(reason,english(965));  /* e^x�� as x�� */
            *next = infinity;
          }
       else
          return 1;
       HIGHLIGHT(*next);
       return 0;
     }
  /* Now FUNCTOR(t)==LIM */
  u = LIMITAND(t);
  if(FUNCTOR(u) != '^' || !equals(ARG(0,u),eulere))
     return 1;
  v = ARG(1,u);
  mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
  err = limval(mid,&ans);
  if(err)
     return 1;
  if(!NOTDEFINED(ans))
     return 1;
  *next = ans;
  if (equals(ans,infinity))
     strcpy(reason,english(965));   /* e^x�� as x�� */
  else
     return 1;
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limexpinf2(term t, term arg, term *next, char *reason)
/*  and lim(x->-�,e^x) = 0 */
{ term u,v,mid,ans;
  int err;
  if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= '^')
     return 1;
  if(FUNCTOR(t)=='^')
     { if(!equals(ARG(0,t),eulere))
           return 1;
       u = ARG(1,t);
       if(!NOTDEFINED(u))
           return 1;
       *next = u;
       if(equals(u,minusinfinity))
          { strcpy(reason,english(966));  /* e^x�\60 as x�-� */
            *next = zero;
          }
       else
          return 1;
       HIGHLIGHT(*next);
       return 0;
     }
  /* Now FUNCTOR(t)==LIMIT */
  u = LIMITAND(t);
  if(FUNCTOR(u) != '^' || !equals(ARG(0,u),eulere))
     return 1;
  v = ARG(1,u);
  mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
  err = limval(mid,&ans);
  if(err)
     return 1;
  if(!NOTDEFINED(ans))
     return 1;
  if (!equals(ans,minusinfinity))
     return 1;
  strcpy(reason,english(966));   /* e^x�\60 as x�-� */
  *next = zero;
  HIGHLIGHT(*next);
  return 0;
}

/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limlnright(term t, term arg, term *next, char *reason)
/*  lim(x->�,ln x) = � */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= LN)
     return 1;
  return limunary_aux(LN,t,next,reason);
}

/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limarctaninf(term t, term arg, term *next, char *reason)
/*  lim(x->�,arctan x) = pi/2 */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ATAN)
     return 1;
  return limunary_aux(ATAN,t,next,reason);
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limtanhinf(term t, term arg, term *next, char *reason)
/*  lim(x->�,tanh x) = 1 */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= TANH)
     return 1;
  return limunary_aux(TANH,t,next,reason);
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limarccotinf(term t, term arg, term *next, char *reason)
/*  lim(x->�,arccot x) = 0 */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ACOT)
     return 1;
  if(!equals(ARG(1,ARG(0,t)),infinity))
     return 1;
  return limunary_aux(ACOT,t,next,reason);
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limarccotinf2(term t, term arg, term *next, char *reason)
/*  lim(x->-�,arccot x) = � */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ACOT)
     return 1;
  if(!equals(ARG(1,ARG(0,t)),minusinfinity))
     return 1;
  return limunary_aux(ACOT,t,next,reason);
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limsqrtinf(term t, term arg, term *next, char *reason)
/*  lim(x->� ,�x) = � */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= SQRT)
     return 1;
  return limunary_aux(SQRT,t,next,reason);
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limrootinf(term t, term arg, term *next, char *reason)
/*  lim(x->�, ��x) = � */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ROOT)
     return 1;
  return limunary_aux(ROOT,t,next,reason);
}

/*___________________________________________________________________*/
static int limunary_aux(unsigned short g, term t, term *next, char *reason)
/* finish off a limit at infinity of g(x) */
/*  g is either LN, ROOT, SQRT, ATAN, or TANH */
/*  t is either a limit or a ln, arctan, root, or sqrt of infinity */
{ unsigned short f = FUNCTOR(t);
  term u,v,mid,ans;
  int err;
  if(f==LN || f== SQRT || f == ROOT || f == ATAN || f == TANH || f == ACOT)
     { u = (f==ROOT ? ARG(1,t) : ARG(0,t));
       if(!NOTDEFINED(u))
          return 1;
       if(equals(u,infinity))
          { switch(f)
               { case LN:
                    strcpy(reason, "$$lim(t->infinity,ln t) = infinity$$");
                    *next = infinity;
                    break;
                 case SQRT:
                    strcpy(reason, "$$lim(t->infinity,sqrt t) = infinity$$");
                    *next = infinity;
                    break;
                 case ROOT:
                    strcpy(reason, "$$lim(t->infinity,root(n,t)) = infinity$$");
                    *next = infinity;
                    break;
                 case ATAN:
                    strcpy(reason,"$$lim(x->infinity,arctan x)=pi/2$$");
                    *next = make_fraction(pi,two);
                    break;
                 case ACOT:
                    strcpy(reason,"$$lim(x->infinity,arccot x)=0$$");
                    *next = zero;
                    break;
                 case TANH:
                    strcpy(reason,"$$lim(x->infinity,tanh x) = 1$$");
                    *next = one;
                    break;

               }
          }
       else if(f == ATAN && equals(u,minusinfinity))
          { strcpy(reason,"$$lim(x->-infinity,arctan x)=-pi/2$$");
            *next = tnegate(make_fraction(pi,two));
          }
       else if(f == TANH && equals(u,minusinfinity))
          { strcpy(reason,"$$lim(x->-infinity,tanh x) = -1$$");
            *next = minusone;
          }
       else if(f == ACOT && equals(u,minusinfinity))
          { strcpy(reason,"$$lim(x->-infinity,arccot x)=pi$$");
            *next = pi;
          }
       else if(f == ROOT && equals(u,minusinfinity) && isodd(ARG(0,t)))
          { *next = minusinfinity;
            strcpy(reason,"$lim(x�-�,��x) = -�$   ");
            strcat(reason, english(2240));    /* (n odd) */
          }
       else
          { *next = undefined;
            strcpy(reason, english(849)); /* undefined limit */
          }
       HIGHLIGHT(*next);
       return 0;
     }
  /* Now  f==LIMIT */
  u = LIMITAND(t);
  f = FUNCTOR(u);
  if(f != g)
     return 1;
  v = (f==ROOT ? ARG(1,u) : ARG(0,u));
  mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
  err = limval(mid,&ans);
  if(err)
     return 1;
  if(!NOTDEFINED(ans))
     return 1;
  if(equals(ans,minusinfinity))
     { switch(g)
          { case ATAN:
               strcpy(reason,"$$lim(x->-infinity,arctan x)=-pi/2$$");
               *next = tnegate(make_fraction(pi,two));
               HIGHLIGHT(*next);
               return 0;
            case ACOT:
               strcpy(reason,"$$lim(x->-infinity,arccot x)=pi$$");
               *next = pi;
               HIGHLIGHT(*next);
               return 0;
            case TANH:
               strcpy(reason,"$$lim(x->-infinity,tanh x) = -1$$");
               *next = minusone;
               HIGHLIGHT(*next);
               return 0;
            case ROOT:
               if(isodd(ARG(0,u)))
                  { *next = minusinfinity;
                    HIGHLIGHT(*next);
                    strcpy(reason,"$lim(x�-�,��x) = -�$   ");
                    strcat(reason, english(2240));  /* (n odd) */
                    return 0;
                  }
               break;
          }
       return 1;
     }
  if(equals(ans,infinity))
     { switch(g)
          { case LN:
               strcpy(reason, "$$lim(t->infinity,ln t) = infinity$$");
               *next = infinity;
               break;
            case SQRT:
               strcpy(reason, "$$lim(t->infinity,sqrt t) = infinity$$");
               *next = infinity;
               break;
            case ROOT:
               strcpy(reason, "$$lim(t->infinity,root(n,t) = infinity$$");
               *next = infinity;
               break;
            case ATAN:
               strcpy(reason,"$$lim(x->infinity,arctan x) = pi/2$$");
               *next = make_fraction(pi,two);
               break;
            case TANH:
               strcpy(reason,"$$lim(x->infinity,tanh x) = 1$$");
               *next = one;
               break;
            default:
               return 1;
          }
       HIGHLIGHT(*next);
       return 0;
     }
  if(NOTDEFINED(ans))
     { *next = ans;
       HIGHLIGHT(*next);
       strcpy(reason, english(1371)); /* f(undefined) = undefined */
       return 0;
     }
  return 1;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limthruexp(term t, term arg, term *next, char *reason)
/*  "lim(e^u) = e^(lim u)"*/
/*  in automode, used only for undefined limits that can't be done by limval */
{ term u,x,base,power;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));  /* the limit variable */
  if(FUNCTOR(u) != '^')
     return 1;
  base = ARG(0,u);
  if(depends(base,x))
     return 1;
  power = ARG(1,u);
  *next = make_power(base,ARITY(t)==2  ? limit(ARG(0,t),power) : limit3(ARG(0,t),ARG(1,t),power));
  strcpy(reason,"lim(e^u) = e^(lim u)");  /* change 2 lines below if you change this */
  if(!equals(base,eulere))
     reason[4] = reason[11] = 'c';
  HIGHLIGHT(*next);
  return 0;
}

/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limthrulog(term t, term arg, term *next, char *reason)
/* lim(ln u) = ln(lim u)*/
/*  in automode, used only for undefined limits that can't be done by limval */
{ term u,v;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != LN)
     return 1;
  v = ARG(0,u);
  *next = ARITY(t)==2 ? ln1(limit(ARG(0,t),v)) : ln1(limit3(ARG(0,t),ARG(1,t),v));
  strcpy(reason,"lim(ln u) = ln(lim u)");
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limthrusin(term t, term arg, term *next, char *reason)
/* lim(sin u) = sin(lim u)*/
{ term u,v;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != SIN)
     return 1;
  v = ARG(0,u);
  *next = ARITY(t)==2 ? sin1(limit(ARG(0,t),v)) : sin1(limit3(ARG(0,t),ARG(1,t),v));
  strcpy(reason,"lim(sin u) = sin(lim u)");
  HIGHLIGHT(*next);
  return 0;
}
/*___________________________________________________________________*/
MEXPORT_TRIGCALC int limthrucos(term t, term arg, term *next, char *reason)
/* lim(sin u) = sin(lim u)*/
{ term u,v;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != COS)
     return 1;
  v = ARG(0,u);
  *next = ARITY(t)==2 ? cos1(limit(ARG(0,t),v)) : cos1(limit3(ARG(0,t),ARG(1,t),v));
  strcpy(reason,"lim(cos u) = cos(lim u)");
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int timesinfinity(term t, term arg, term *next, char *reason)
/* lim uv when lim u = � and lim v # 0 */
/*  That is, �nonzero = �  */
{ unsigned short n;
  int i,err;
  term u;
  int flagleft,flagright,flagundef;
  if(FUNCTOR(t) != '*')
     return 1;
  n = ARITY(t);
  flagleft = flagright = flagundef = 0;
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(equals(u,infinity))
          ++flagright;
       else if (equals(u,minusinfinity))
          ++flagleft;
       else if (WILD(u))
          ++flagundef;
     }
  if(flagleft == 0 && flagright == 0 && flagundef == 0)
     return 1;
  if(flagundef)
     { *next = undefined;
       HIGHLIGHT(*next);
       strcpy(reason, english(967));  /* undefined factor */
     }
  if((flagleft || flagright) && contains(t,LIMIT))
     { errbuf(0, english(850));
         /* "First evaluate the other limits in the product. */
       return 1;
     }
  if(flagleft & 1)  /* odd number of minus infinities */
      { *next = minusinfinity;
        strcpy(reason, english(968));
           /* lim uv = -�            if u�-� and lim v # 0 */
      }
  else if(flagright || flagleft)
      { *next = infinity;
        strcpy(reason, english(969));
           /* lim uv = �  if       u�� and lim v # 0 */
      }
  else
     return 1;
  /* We still must make sure the other factors aren't zero */
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(!NOTDEFINED(u))
          { err = infer(nonzero(u));
            if(err)
               { errbuf(0, english(851));
                   /* Can't verify other factors are nonzero. */
                 return 1;
               }
         }
     }
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinitytimesinfinity(term t, term arg, term *next, char *reason)
/*  �� = �  */
{ unsigned short n;
  int i,err;
  term u;
  int flagleft,flagright,flagundef;
  if(FUNCTOR(t) != '*')
     return 1;
  n = ARITY(t);
  flagleft = flagright = flagundef = 0;
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(equals(u,infinity))
          ++flagright;
       else if (equals(u,minusinfinity))
          ++flagleft;
       else if (WILD(u))
          ++flagundef;
     }
  if(flagleft == 0 && flagright == 0 && flagundef == 0)
     return 1;
  if(flagundef)
     { *next = undefined;
       HIGHLIGHT(*next);
       strcpy(reason, english(967));  /* undefined factor */
     }
  if((flagleft || flagright) && contains(t,LIMIT))
     { errbuf(0, english(850));
         /* First evaluate the other limits in the product. */
       return 1;
     }
  if(flagleft & 1)  /* odd number of minus infinities */
      *next = minusinfinity;
  else if(flagright + flagleft > 1)
      *next = infinity;
  else
     return 1;
  /* We still must make sure the other factors aren't zero */
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(!NOTDEFINED(u))
          { err = infer(nonzero(u));
            if(err)
               { errbuf(0, english(851));
                   /* Can't verify other factors are nonzero. */
                 return 1;
               }
         }
     }
  HIGHLIGHT(*next);
  strcpy(reason, "$�� = �$");
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int addinfinity(term t, term arg, term *next, char *reason)
/* lim u+v when lim u = �� and lim v # �� */
/*  That is,  � + finite = �  */
{ unsigned short n;
  int i,err;
  term u;
  int flagleft,flagright,flagundef;
  if(FUNCTOR(t) != '+')
     return 1;
  if(contains_calc(t))
     return 1;  /* no integrals or limits allowed */
  n = ARITY(t);
  flagleft = flagright = flagundef = 0;
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(equals(u,infinity))
          ++flagright;
       else if (equals(u,minusinfinity))
          ++flagleft;
       else if (WILD(u))
          ++flagundef;
       else if(FUNCTOR(u) == '*' && POSNUMBER(ARG(0,u)) && ARITY(u) == 2 && equals(ARG(1,u),infinity))
          ++flagright;  /* accept 2 infinity for example as infinite */
       else if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == '*' && ARITY(ARG(0,u)) == 2 &&
               POSNUMBER(ARG(0,ARG(0,u))) && equals(ARG(1,ARG(0,u)),infinity)
              )
          ++flagleft;   /* accept -2 infinity as minus infinity */
       else if(FUNCTOR(u) == '^' && INTEGERP(ARG(1,u)) && equals(ARG(0,u),infinity))
          ++flagright;  /* accept infinity^3 as infinite */
       else if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == '^' && equals(ARG(0,ARG(0,u)),infinity)
               && POSNUMBER(ARG(1,ARG(0,u)))
              )
          ++flagleft;
       else if(contains(u,INFINITY) || contains(u,BOUNDED_OSCILLATIONS) ||
               contains(u,UNBOUNDED_OSCILLATIONS) || contains(u,UNDEFINED)
              )
          return 1;
     }
  if(flagleft == 0 && flagright == 0 && flagundef == 0)
     return 1;
  if(flagleft && flagright)
     { errbuf(0, english(852));
          /* "You have reached an indeterminate form. */
       errbuf(1, english(853));
          /* Undo back to where these terms were created. */
       return 1;
     }
  if(flagundef)
     { *next = undefined;
       HIGHLIGHT(*next);
       strcpy(reason, english(970)); /* undefined summand */
     }
  if((flagleft || flagright) && contains(t,LIMIT))
     { errbuf(0, english(854));
          /* First evaluate the other limits in the sum. */
       return 1;
     }
  if(flagleft)
      { *next = minusinfinity;
        strcpy(reason, english(971));
           /* lim u+v = -� if         u�-� and lim v #0 */
      }
  else if(flagright)
      { *next = infinity;
        strcpy(reason, english(972));
           /*  lim u+v = � if       u�� and lim v finite */
      }
  else
     return 1;
  /* We still must make sure the other factors are defined */
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(!NOTDEFINED(u))
          { err = infer(domain(u));
            if(err)
               { errbuf(0, english(855));
                    /*  Can't verify that the other summands are defined. */
                 return 1;
               }
         }
     }
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityplusinfinity(term t, term arg, term *next, char *reason)
/*    � + � = �   */
{ unsigned short n;
  int i,err;
  term u;
  int problemtype;
  int flagleft,flagright,flagundef;
  if(FUNCTOR(t) != '+')
     return 1;
  n = ARITY(t);
  flagleft = flagright = flagundef = 0;
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(equals(u,infinity))
          ++flagright;
       else if (equals(u,minusinfinity))
          ++flagleft;
       else if (WILD(u))
          ++flagundef;
     }
  if(flagleft == 0 && flagright == 0 && flagundef == 0)
     return 1;
  if(flagleft && flagright)
     { errbuf(0, english(852));
          /* "You have reached an indeterminate form. */
       problemtype = get_problemtype();
       if(problemtype == LHOPITAL || problemtype == LIMITS)
          errbuf(1, english(853));
          /* Undo back to where these terms were created. */
       return 1;
     }
  if(flagundef)
     { *next = undefined;
       HIGHLIGHT(*next);
       strcpy(reason, english(970)); /* undefined summand */
     }
  if((flagleft || flagright) && contains(t,LIMIT))
     { errbuf(0, english(854));
          /* First evaluate the other limits in the sum. */
       return 1;
     }
  if(flagleft > 1)
     *next = minusinfinity;
  else if(flagright > 1)
     *next = infinity;
  else
     return 1;
  /* We still must make sure the other factors are defined */
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(!NOTDEFINED(u))
          { err = infer(domain(u));
            if(err)
               { errbuf(0, english(855));
                    /*  Can't verify that the other summands are defined. */
                 return 1;
               }
         }
     }
  HIGHLIGHT(*next);
  strcpy(reason, "$� + � = �$");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityminusinfinity(term t, term arg, term *next, char *reason)
/*    � + � = �   */
{ unsigned short n;
  int i;
  term u;
  int flagleft,flagright,flagundef;
  if(FUNCTOR(t) != '+')
     return 1;
  n = ARITY(t);
  flagleft = flagright = flagundef = 0;
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(equals(u,infinity))
          ++flagright;
       else if (equals(u,minusinfinity))
          ++flagleft;
       else if (WILD(u))
          ++flagundef;
     }
  if(flagleft == 0 && flagright == 0 && flagundef == 0)
     return 1;
  if(flagleft && flagright)
     { *next = undefined;
       HIGHLIGHT(*next);
       strcpy(reason, "$� - � = undefined$");
       return 0;
     }
  return 1;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityovernonzero(term t, term arg, term *next, char *reason)
{ term num,den;
  int sign;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  den = ARG(1,t);
  if(NOTDEFINED(den))
     { errbuf(0, english(856));
          /* denominator must be defined and nonzero. */
       return 1;
     }
  if(!NOTDEFINED(num))
     return 1;
  if(contains(den,LIMIT))
     { errbuf(0, english(1958));
       /* First evaluate the limit. */
       return 1;
     }
  sign = get_sign(den);
  if(sign == 0)
     { errbuf(0, english(857));
          /*  denominator must be nonzero */
       return 1;
     }
  if(WILD(num) || sign > 0)
     *next = num;
  else if(sign < 0)
     tneg(num,next);
  HIGHLIGHT(*next);
  strcpy(reason, english(859));
     /* lim(u/v) = lim u if   lim v #0, lim u =�� */
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int nonzerooverinfinity(term t, term arg, term *next, char *reason)
{ term num,den;
  int err;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  den = ARG(1,t);
  if(NOTDEFINED(num))
     { errbuf(0, english(860));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(!NOTDEFINED(den))
     return 1;
  err = check(nonzero(num));
  if(err)
     { errbuf(0, english(861));
          /* numerator must be nonzero */
       return 1;
     }
  if(WILD(den))
      return 1;   /*  *next = undefined; */
  else
      *next = zero;
  strcpy(reason, english(862));
      /* "lim(u/v) = 0 if      lim u #0, lim v =�� */
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int zerodenom3(term t, term arg, term *next, char *reason)
{ term num,denom;
  if(FUNCTOR(t) != '/')
     return 1;
  denom = ARG(1,t);
  num = ARG(0,t);
  if(!ISZERO(denom))
     return 1;
  if(NOTDEFINED(num))
     { errbuf(0, english(863));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(contains(num,LIMIT))
     { errbuf(0, english(864));
         /* First evaluate the numerator */
       return 1;
     }
  if(!POSITIVE_INFINITESIMAL(t) && !NEGATIVE_INFINITESIMAL(t))
     { *next = undefined;
       strcpy(reason,english(938));  /* a/0 = undefined */
       /* no point trying to find the sign of the numerator */
       HIGHLIGHT(*next);
       return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int zerodenom(term t, term arg, term *next, char *reason)
{ term num,denom;
  int err;
  if(!FRACTION(t))
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(!ISZERO(denom))
     return 1;
  if(NOTDEFINED(num))
     { errbuf(0, english(863));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(contains(num,LIMIT))
     { errbuf(0, english(864));
         /* First evaluate the numerator */
       return 1;
     }
  if(!POSITIVE_INFINITESIMAL(t))
     return 1;
  err = infer(lessthan(zero,num));
  if(!err)
     { *next = infinity;
       strcpy(reason, english(939)); /* a/0+ = � if a>0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       release(arithmetic);
       return 0;
     }
  err = infer(lessthan(num,zero));
  if(!err)
     { *next = minusinfinity;
       strcpy(reason, english(941));  /* a/0+ = -� if a<0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       release(arithmetic);
       return 0;
     }
  *next = undefined;
  strcpy(reason, english(938));
  HIGHLIGHT(*next);
  commentbuf(0,english(865));
     /* Can't determine sign of numerator */
  release(polyvalop);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int zerodenom2(term t, term arg, term *next, char *reason)
{ term num,denom;
  int err;
  if(!FRACTION(t))
     return 1;
  denom = ARG(1,t);
  num = ARG(0,t);
  if(!ISZERO(denom))
     return 1;
  if(NOTDEFINED(num))
     { errbuf(0, english(863));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(contains(num,LIMIT))
     { errbuf(0, english(864));
         /* First evaluate the numerator */
       return 1;
     }
  if(!NEGATIVE_INFINITESIMAL(t))
     return 1;
  err = infer(lessthan(zero,num));
  if(!err)
     { *next = minusinfinity;
       strcpy(reason, english(940)); /* a/0- = -� if a>0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       release(arithmetic);
       return 0;
     }
  err = infer(lessthan(num,zero));
  if(!err)
     { *next = infinity;
       strcpy(reason, english(942)); /* a/0- = � if a<0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       return 0;
     }
  *next = undefined;
  strcpy(reason, english(938));
  HIGHLIGHT(*next);
  commentbuf(0,english(865));
     /* Can't determine sign of numerator */
  release(polyvalop);
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityoverzero(term t, term arg, term *next, char *reason)
{ term num, denom;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(!ISZERO(denom))
     return 1;
  if(equals(num,infinity) && POSITIVE_INFINITESIMAL(t))
     { *next = infinity;
       HIGHLIGHT(*next);
       strcpy(reason,"$�/0+ = �$");
       return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityoverzerosq(term t, term arg, term *next, char *reason)
{ term num, denom;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(FUNCTOR(denom)!= '^')
     return 1;
  if(!equals(ARG(1,denom),two))
     return 1;
  if(!ZERO(ARG(0,denom)))
     return 1;
  if(equals(num,infinity))
     { *next = infinity;
       HIGHLIGHT(*next);
       strcpy(reason,"$�/0^2 = �$");
       return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityoverzero2n(term t, term arg, term *next, char *reason)
{ term num, denom;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(FUNCTOR(denom)!= '^')
     return 1;
  if(!iseven(ARG(1,denom)))
     return 1;
  if(!ZERO(ARG(0,denom)))
     return 1;
  if(equals(num,infinity))
     { *next = infinity;
       HIGHLIGHT(*next);
       strcpy(reason,"$�/0^2� = �$");
       return 0;
     }
  return 1;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityoverzero2(term t, term arg, term *next, char *reason)
{ term num, denom;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(!ISZERO(denom))
     return 1;
  if(equals(num,infinity) && NEGATIVE_INFINITESIMAL(t))
     { *next = minusinfinity;
       HIGHLIGHT(*next);
       strcpy(reason,"$�/0- = -�$");
       return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int infinityoverzero3(term t, term arg, term *next, char *reason)
{ term num, denom;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(!ISZERO(denom))
     return 1;
  if(equals(num,infinity) &&
     !NEGATIVE_INFINITESIMAL(t) &&
     !POSITIVE_INFINITESIMAL(t)
    )
     { *next = undefined;
       HIGHLIGHT(*next);
       strcpy(reason,"$�/0$ = undefined");
       commentbuf(0,english(858));
         /* !Sign of denominator unknown */
       return 0;
     }
  return 1;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int toinfinity1(term t, term arg, term *next, char *reason)
/* u^� = � if u > 1 */

{ term u;
  int err;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  if(!equals(ARG(1,t),infinity))
     return 1;
  if(NOTDEFINED(u))
     return 1;
  err = infer(lessthan(one,u));
  if(err)
     { errbuf(0, english(866));
          /* base must exceed 1 */
       return 1;
     }
  *next = infinity;
  HIGHLIGHT(*next);
  strcpy(reason,"$u^� = � (u > 1)$");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int toinfinity0(term t, term arg, term *next, char *reason)
/* u^� = 0 if 0 < u < 1 */

{ term u;
  int err;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  if(!equals(ARG(1,t),infinity))
     return 1;
  if(NOTDEFINED(u))
     return 1;
  err = infer(lessthan(zero,u));
  if(err)
     { errbuf(0, english(867));
         /* Base must be positive */
       return 1;
     }
  err = infer(lessthan(u,one));
  if(err)
     { errbuf(0, english(868));
          /* Base must be less than 1 */
       return 1;
     }
  *next = zero;
  HIGHLIGHT(*next);
  strcpy(reason, english(958));  /* u^� = 0 if 0 < u < 1 */
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int tominusinfinity1(term t, term arg, term *next, char *reason)
/* "u^(-�) = 0 (u > 1)", */

{ term u;
  int err;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  if(!equals(ARG(1,t),minusinfinity))
     return 1;
  if(NOTDEFINED(u))
     return 1;
  err = infer(lessthan(one,u));
  if(err)
     { errbuf(0, english(869));
          /* Base must exceed 1 */
       return 1;
     }
  *next = zero;
  HIGHLIGHT(*next);
  strcpy(reason, english(973));  /*  u^(-�) = 0 if u > 1 */
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int tominusinfinity0(term t, term arg, term *next, char *reason)
/*  "u^(-�) = �  (0<u<1)", */
{ term u;
  int err;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  if(!equals(ARG(1,t),minusinfinity))
     return 1;
  if(NOTDEFINED(u))
     return 1;
  err = infer(lessthan(zero,u));
  if(err)
     { errbuf(0, english(867));
         /* Base must be positive */
       return 1;
     }
  err = infer(lessthan(u,one));
  if(err)
     { errbuf(0, english(868));
          /* Base must be less than 1 */
       return 1;
     }
  *next = infinity;
  HIGHLIGHT(*next);
  strcpy(reason, english(974));  /* u^(-�) = � if 0<u<1 */
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int lninfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= LN && FUNCTOR(t) != LOG)
     return 1;
  u = ARG(0,t);
  if(!equals(u,infinity))
     return 1;
  *next = infinity;
  strcpy(reason, "$lim(x��,ln x) = �$");
  HIGHLIGHT(*next);
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int lnzero(term t, term arg, term *next, char *reason)
/* ln 0 = -infinity */
{ term u;
  if(FUNCTOR(t)!= LN && FUNCTOR(t) != LOG)
     return 1;
  u = ARG(0,t);
  if(!ZERO(u))
     return 1;
  *next = minusinfinity;
  strcpy(reason, "$lim(x�0+,ln x) = -�$");
  HIGHLIGHT(*next);
  return 0;
}


/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int sqrtinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= SQRT)
     return 1;
  u = ARG(0,t);
  if(!equals(u,infinity))
     return 1;
  *next = infinity;
  strcpy(reason, english(957));  /* �x�� as x�� */
  HIGHLIGHT(*next);
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int rootinfinity(term t, term arg, term *next, char *reason)
{ term u,index;
  int err;
  if(FUNCTOR(t)!= ROOT)
     return 1;
  u = ARG(1,t);
  index = ARG(0,t);
  if(!NOTDEFINED(u))
     return 1;
  if(equals(u,infinity))
     { *next = infinity;
       strcpy(reason, english(956));  /*  ��x�� as x�� */
       HIGHLIGHT(*next);
       return 0;
     }
  err = infer(odd(index));
  if(!err)
     { *next = minusinfinity;
       strcpy(reason, english(955)); /* ��x�-� as x�-�, n odd */
       HIGHLIGHT(*next);
       return 0;
     }
  *next = undefined;
  HIGHLIGHT(*next);
  strcpy(reason, english(954));  /* n not odd in �� */
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int powerofinfinity(term t, term arg, term *next, char *reason)
/* infinity ^n = infinity if n > 0 */
{ term u;
  int err;
  if(FUNCTOR(t)!= '^')
     return 1;
  u = ARG(0,t);
  if(!equals(u,infinity))
     return 1;
  err = infer(lessthan(zero,ARG(1,t)));
  if(err)
     return 1;
  *next = infinity;
  strcpy(reason, english(1116));  /* x��� as x�� if n>0 */
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int ataninfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= ATAN)
     return 1;
  u = ARG(0,t);
  if(!NOTDEFINED(u))
     return 1;
  if(equals(u,infinity))
      { *next = make_fraction(pi,two);
        strcpy(reason, "$$lim(x->infinity,arctan x)=pi/2$$");
      }
  else if(equals(u,minusinfinity))
      { *next = tnegate(make_fraction(pi,two));
         strcpy(reason, "$$lim(x->infinity,arctan x) = -pi/2$$");
      }
  else
     return 1;
  HIGHLIGHT(*next);
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int acotinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= ACOT)
     return 1;
  u = ARG(0,t);
  if(!NOTDEFINED(u))
     return 1;
  if(!equals(u,infinity))
     return 1;
  *next = zero;
  strcpy(reason, "$lim(x��,arccot x)=0$");
  HIGHLIGHT(*next);
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int acotminusinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= ACOT)
     return 1;
  u = ARG(0,t);
  if(!NOTDEFINED(u))
     return 1;
  if(!equals(u,minusinfinity))
     return 1;
   *next = pi;
  strcpy(reason, "$$lim(x->-infinity,arccot x)=pi$$");
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int asecinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= ASEC)
     return 1;
  u = ARG(0,t);
  if(!ISINFINITE(u))
     return 1;
  *next = make_fraction(pi,two);
  strcpy(reason, "$$lim(x->infinity,arcsec x)=pi/2$$");
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int acscinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= ACSC)
      return 1;
  u = ARG(0,t);
  if(!ISINFINITE(u))
     return 1;
  *next = zero;
  if(NEGATIVE(u))
     strcpy(reason, "$$lim(x->-infinity,arccsc x)=0$$");
  else
     strcpy(reason, "$$lim(x->infinity,arccsc x)=0$$");
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int triginfinity(term t, term arg, term *next, char *reason)
{ term u;
  char buffer[12];
  unsigned short f = FUNCTOR(t);
  if(f==SIN || f==COS)
    { u = ARG(0,t);
      if (equals(u,infinity) || equals(u,minusinfinity))
           *next = bounded_oscillations;
      else
         return 1;
    }
 else if(f==TAN || f == SEC || f == CSC || f == COT)
    { u = ARG(0,t);
      if (equals(u,infinity) || equals(u,minusinfinity))
          *next = unbounded_oscillations;
      else
         return 1;
    }
 else
    return 1;
 functor_string(f,SCREEN,buffer);
 strcpy(reason,"$lim(x��,$");
 strcat(reason, buffer);
 strcat(reason,"( x ) ");
 strcat(reason, english(2181));  /* is       undefined */
 HIGHLIGHT(*next);
 return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int coshinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= COSH)
     return 1;
  u = ARG(0,t);
  if(!ISINFINITE(u))
     return 1;
  *next = infinity;
  if(NEGATIVE(u))
     strcpy(reason, "$$lim(x->-infinity,cosh x)=infinity$$");
  else
     strcpy(reason, "$$lim(x->infinity,cosh x)=infinity$$");
  HIGHLIGHT(*next);
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int sinhinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= SINH)
     return 1;
  u = ARG(0,t);
  if(!ISINFINITE(u))
     return 1;
  if(equals(u,infinity))
     { *next = infinity;
       strcpy(reason, "$lim(x��,sinh x) = �$");
     }
  else  /* u is minusinfinity */
     { *next = minusinfinity;
        strcpy(reason, "$lim(x�-�,sinh x)=-�$");
     }
  HIGHLIGHT(*next);
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int tanhinfinity(term t, term arg, term *next, char *reason)
{ term u;
  if(FUNCTOR(t)!= TANH)
     return 1;
  u = ARG(0,t);
  if(!ISINFINITE(u))
     return 1;
  if(equals(u,infinity))
     { *next = one;
       strcpy(reason, "$lim(x��,sinh x) = 1$");
     }
  else  /* u is minusinfinity */
     { *next = minusone;
        strcpy(reason, "$lim(x�-�,sinh x)=-1$");
     }
  HIGHLIGHT(*next);
  return 0;
}

/*______________________________________________________________________*/
MEXPORT_TRIGCALC int rationalizesum(term t, term arg, term *next, char *reason)
/* Example:  lim(x->-infinity, x + �(x^2-1)).
   See rationalize_ok for other examples where we do and don't
   want this used.  */

{ term u,v,s;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != '+')
     return 1;
  if(get_mathmode() == AUTOMODE && !rationalize_ok(t))
     /* check for examples where this shouldn't be used, see above */
     return 1;
  v = make_term('/',2);
  ARGREP(v,0,u);
  ARGREP(v,1,one);   /* construct v = u/1.  You can't use make_fraction
                        as it discards denominators of 1   */
  s = ARITY(t) == 2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
  err = rationalizenum(s,arg,next,reason);
  /* rationalizenum calls set_pathtail with the result that the
  path to the sum is selected. */
  if(err)
     { RELEASE(s);
       return 1;
     }
  SetShowStepOperation(rationalizenum);
  return 0;
}
/*______________________________________________________________________*/
MEXPORT_TRIGCALC int limleadingterms(term t, term arg, term *next, char *reason)
/* lim u/v  = lim (leading-term(u)/leading-term(v))  */
{ term a,x,u,v,w,num,denom,c,deg,c2,deg2,newnum,newdenom;
  int err,numflag=0,denomflag=0;
  int n = ARITY(t);
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  a = ARG(1,ARG(0,t));
  if(FRACTION(u))
     { num = ARG(0,u);
       denom = ARG(1,u);
       err = leading_term(num,x,a,&c,&deg);
       if(err)
          return 1;
       err = leading_term(denom,x,a,&c2,&deg2);
       if(err)
          return 1;
       err = infer(nonzero(c));
       if(err)
          return 1;
       err = infer(nonzero(c2));
       if(err)
          return 1;
       w = (ZERO(a) || ISINFINITE(a)) ? x : sum(x,tnegate(a));
       newnum = ZERO(deg) ? c : signedproduct(c,make_power(w,deg));
       newdenom = ZERO(deg2) ? c2: signedproduct(c2, make_power(w,deg2));
       if(!equals(newdenom,denom))
          { HIGHLIGHT(newdenom);
            denomflag = 1;
          }
       if(!equals(newnum,num))
          { HIGHLIGHT(newnum);
            numflag = 1;
          }
       if(!numflag && !denomflag)
          return 1;
       v = make_fraction(newnum,newdenom);
       *next = n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
       strcpy(reason, english(1146));
          /* use leading term */
       if(numflag && denomflag)
          { commentbuf(0, english(1112));
            /* lim((u+a)/(v+b))=lim(u/v)  if a/u�0 and b/v�0 */
            commentbuf(1, english(1149));
            /* Here u and v are the leading terms of num and denom */
          }
       else if (numflag)
          { commentbuf(0, english(1113));
            /* lim((u+a)/v) = lim(u/v)  if a/u�0 */
            commentbuf(1, english(1147));
            /* Here u is the leading term of the numerator. */
          }
       else
          { commentbuf(0, english(1114));
            /* lim(u/(v+b)) = lim(u/v)  if b/v�0",  */
            commentbuf(1, english(1148));
            /* Here v is the leading term of the denominator */
          }
       return 0;
     }
  return 1;
}
/*______________________________________________________________________*/
MEXPORT_TRIGCALC int limleadingterm(term t, term arg, term *next, char *reason)
  /* lim(u+a)=lim(u)  if a/u�0 */
{ term a,x,u,v,w,c,deg;
  int err;
  int n = ARITY(t);
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  a = ARG(1,ARG(0,t));
  if(FRACTION(u))
     { errbuf(0, english(1393));
       /* There is a similar operation that works on fractions */
       return 1;
     }
  /* Now it's not a fraction */
  err = leading_term(u,x,a,&c,&deg);
  if(err && get_mathmode() == AUTOMODE)
     return 1;
  w = (ZERO(a) || ISINFINITE(a)) ? x : sum(x,tnegate(a));
  if(ZERO(deg))
     return 1;
  v = product(c, ONE(deg)? w : make_power(w,deg));
  if(equals(v,u))
     return 1;
  HIGHLIGHT(v);
  *next = n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
  strcpy(reason, english(1115));
  /* lim(u+a)=lim(u)  if a/u�0 */
  return 0;
}
/*______________________________________________________________________*/
static int slt_aux(term u, term x, term *ans, char *reason)
/* examine subterms of u, stopping if any functor
except /, *, ^, SQRT, and ROOT is encountered, and also
stopping at '^' if the exponent depends on x.
Look for a sum to which to apply sumleadingterm.
If found, substitute the
result for that sum and return it in *ans.  Return 0 for
success, 1 for failure.  Don't go into exponents, because of
examples like e^(x^2/(1-x)) e^-(x^2/(1+x)); if you apply
sumleading term to the 1-x and 1+x, you will get the wrong answer.
See ok_leadingterm in selectop.c for more examples.
*/

{ int i,j,err;
  unsigned short n,f;
  term temp;
  f = FUNCTOR(u);
  if(ATOMIC(u))
     return 1;
  if(f == '+')
     return sumleadingterm(u,zero,ans,reason);
  if(f != '*' && f != '/' && f != ROOT && f != SQRT && f != '^')
      return 1;
  if(f == '^')  /* don't use it in the exponent, only in the base */
     { if(depends(ARG(1,u),x))
          { errbuf(0, english(1513));
            /* Can't use leading terms because exponent is not constant. */
            return 1;
          }
       err = slt_aux(ARG(0,u),x,&temp,reason);
       if(err)
          return 1;
       *ans = make_power(temp,ARG(1,u));
       return 0;
     }

  n = ARITY(u);
  for(i=0;i<n;i++)
     { err = slt_aux(ARG(i,u),x,&temp,reason);
       if(!err)
          break;
     }
  if(i == n)
     return 1;
  *ans = make_term(f,n);
  for(j=0;j<n;j++)
     ARGREP(*ans,j, i==j ? temp : ARG(j,u));
  return 0;
}

/*______________________________________________________________________*/
static int use_comdenom_instead(term x, term a, term s)
/* s is a sum,  and lim(x->a,s) can be done by sumleadingterm, but
if we would rather not do so, but use commondenomandsimp instead
(presumably to be followed by L'Hopital's rule)  then return 1.
Else return 0.
Example:  lim(x->1, 1/ln(x) + 1/(x-1))
It's better to show a longer solution, except in case the leading 
terms of each summand are obvious and they don't cancel out.
*/
{ term c,deg;
  int err;
  if(FUNCTOR(s) != '+')
     return 0;  /* assert(0) */
  err = lt_plus(ARGPTR(s),ARITY(s),x,a,&c,&deg);
  if(err)
      return 0;   /* this shouldn't happen, since sumleadingterm does work. */
  if(ZERO(c))   /* the leading terms of the summands do cancel out */
      return 1;
  return 0;
}


/*______________________________________________________________________*/
MEXPORT_TRIGCALC int sumleadingterm(term u, term arg, term *next, char *reason)
/* replace a sum u by its leading term, provided
u occurs inside a limit, and the path from the LIMIT to u does
not include any sums.  Indeed it should include only products,
quotients, roots, sqrts, and constant powers.

Example:  in lim (x->infinity, x^2/(x-1) - x^2/(x+1)) you will
get the incorrect answer 0 if you apply this operation to the
sums in the denominator.  See ok_sumleadingterm in selectops.c
for discussion of when this operation can be used.

In automode the operation is applied only to limit terms,
rather than directly to sums, as it is in term selection mode.
*/

{ term a,x,c,deg,dir,v,w,q,logdeg,s;
  int err;
  unsigned short path[MAXTAIL];
  unsigned short  n = ARITY(u);
  if(get_mathmode == MENUMODE && FUNCTOR(u) != LIMIT)
      return 1;
  if(FUNCTOR(u) == LIMIT)
     /* menu mode or auto mode or term selection mode */
     { x = ARG(0,ARG(0,u));  /* the limit variable */
       s = LIMITAND(u);
       err = slt_aux(s,x,&v,reason);
       if(err)
           return 1;
       /* in some cases it would be more instructive to use
       common denoms followed by L'Hopital, e.g. lim(x->1, 1/ ln(x) + 1/(x-1)).
       We can't control this from postops since in general we
       don't want to use common denoms inside limits.  So,
       we do it here instead. */
       a = ARG(1,ARG(0,u));
       if(FUNCTOR(s) == '+' && use_comdenom_instead(x,a,s))
          { err = commondenomandsimp(s,zero,&v,reason);
            *next = n==2 ? limit(ARG(0,u),v) : limit3(ARG(0,u),ARG(1,u),v);
            SetShowStepOperation(commondenomandsimp);
            path[0] = LIMIT;
            path[1] = 2;
            path[2] = 0;
            set_pathtail(path);
            return 0;
          }
       *next = n==2 ? limit(ARG(0,u),v) : limit3(ARG(0,u),ARG(1,u),v);
       path_to_difference(u,*next,path,1);
       set_pathtail(path);
       return 0;
     }
  /* in term selection mode it's applied to sums.*/
  if(FUNCTOR(u) != '+')
     return 1;
  /*  Now we need to know the limit variable x and the limit point a
      such that u is inside lim(x->a,...) */
  err = get_limit_info(&x,&a,&dir);
  if(err)
     return 1;  /* not inside a limit */
  err = leading_term(u,x,a,&c,&deg);
  if(!err)
     { if(ZERO(c))
          return 1;
       if(!ZERO(a) && !ISINFINITE(a))
          x = sum(x,tnegate(a));
       if(ZERO(deg))
          *next = c;
       else if(ONEHALF(deg) && contains(u,SQRT))
          *next = product(c,sqrt1(x));
       else if(ONE(deg))
          *next = product(c,x);
       else if(NEGATIVE(deg))
          *next = make_fraction(c, make_power(x,ARG(0,deg)));
       else
          *next = product(c,make_power(x,deg));
       goto succeed;
     }
  /* Don't give up, e.g. in sqrt(x + ln x) as x goes to infinity
     we should be able to drop the ln x.
     Also in sqrt(x) - sqrt(x) ln x  we should be able to drop
     the sqrt(x) term. */
  err = log_leading_term(u,x,a,&c,&deg,&logdeg);
  if(err)
     return 1;
  /* prepare the non-logarithmic part q first */
  if(ZERO(c))
     return 1;
  if(!ZERO(a) && !ISINFINITE(a))
     x = sum(x,tnegate(a));
  if(ZERO(deg))
     q = c;
  else if(ONE(deg))
     q = product(c,x);
  else if(ONEHALF(deg) && contains(u,SQRT))
     q = product(c,sqrt1(x));
  else if(NEGATIVE(deg))
     q  = make_fraction(c, make_power(x,ARG(0,deg)));
  else
     q = product(c,make_power(x,deg));
  if(ZERO(logdeg))
     { *next = q;
       goto succeed;
     }
  if(NEGATIVE(logdeg))
     { w = make_power(ln1(x),ARG(0,logdeg));
       if(FRACTION(q))
          { *next = make_fraction(ARG(0,q),product(ARG(1,q),w));
            goto succeed;
          }
       *next = make_fraction(q,w);
       goto succeed;
     }
  else
     { w = ONE(logdeg) ? ln1(x) : make_power(ln1(x),logdeg);
       if(FRACTION(q))
          { *next = make_fraction(product(ARG(0,q),w),ARG(1,q));
            goto succeed;
          }
       *next = product(q,w);
       goto succeed;
     }
  succeed:
     strcpy(reason, english(1512));  /* leading term */
     HIGHLIGHT(*next);
     return 0;
}


/*_____________________________________________________________*/
int rationalize_ok(term t)
/* t is a limit term with a limitand that is a sum or fraction.
Return 1 if it's a good idea to rationalize; that is, (for finite limits)
if some summand contains a sqrt (or root or abs) and the
whole limit is zero.  Return 0 otherwise.
Remove any assumptions that are made during the calculations.
*/

/* We want rationalize_sum used on lim(x->-infinity,x+�(x^2-1)),
   where the limit itself is not zero.  But we
   don't want to use rationalize_sum on lim(x->-infinity,x-�(x^2-1))
   where both summands go to -infinity; we just want to use
   limsum on that, otherwise we will loop.  We only use it if the
   limvals of the two summands are opposite.
   At finite limits we just look for the limit to be zero. */


{ term u,a,c;
  int err;
  short savenextassumption = get_nextassumption();
  term newlim;
  unsigned short n = ARITY(t);
  assert(FUNCTOR(t)==LIMIT);
  u = LIMITAND(t);
  if(FRACTION(u))
     { if(FUNCTOR(ARG(1,u)) == '+' && FUNCTOR(ARG(0,u)) != '+')
          u = ARG(1,u);
       else if(FUNCTOR(ARG(0,u)) == '+' && FUNCTOR(ARG(1,u)) != '+')
          u = ARG(0,u);
       else if(FUNCTOR(ARG(0,u)) == '+' && FUNCTOR(ARG(1,u)) == '+')
          { if(contains(ARG(1,u),SQRT) || contains(ARG(1,u),ROOT) || contains(ARG(1,u),ABS))
               u = ARG(1,u);
            else
               u = ARG(0,u);
          }
       else
          return 0;
     }
  else if(!contains(u,SQRT) && !contains(u,ROOT) && !contains(u,ABS))
     return 0;
  if(FUNCTOR(u) != '+')
     return 0;
  a = ARG(1,ARG(0,t));
  if(NOTDEFINED(a))
     { if(ARITY(u) == 2)
          { /* just check that the limits are both infinite, but of
               opposite signs */
            term lim1 = n==2 ? limit(ARG(0,t),ARG(0,u)) : limit3(ARG(0,t),ARG(1,t),ARG(0,u));
            term lim2 = n==2 ? limit(ARG(0,t),ARG(1,u)) : limit3(ARG(0,t),ARG(1,t),ARG(1,u));
            term ans1, ans2;
            err = limval(lim1, &ans1);
            set_nextassumption(savenextassumption);
            if(err || !NOTDEFINED(ans1))
               return 0;
            err = limval(lim2, &ans2);
            set_nextassumption(savenextassumption);
            if(err || !NOTDEFINED(ans2))
               return 0;
            return 1;
          }
       else
          return 0;
     }
  /* Now at finite limits */
  newlim = ARITY(t) == 2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
  err= limval(newlim,&c);
  set_nextassumption(savenextassumption);
  if(err || !ZERO(c))
     return 0;
  return 1;
}
/*____________________________________________________*/
static int contains_undefined(term t)
/* return 1 if t contains UNDEFINED, BOUNDED_OSCILLATIONS, or
UNBOUNDED_OSCILLATIONS */
{ unsigned short n = ARITY(t);
  int i;
  unsigned short f = FUNCTOR(t);
  if(OBJECT(t))
     return 0;
  if(n == 0 && (f == UNDEFINED || f == BOUNDED_OSCILLATIONS || f == UNBOUNDED_OSCILLATIONS))
     return 1;
  for(i=0;i<n;i++)
     { if(contains_undefined(ARG(i,t)))
          return 1;
     }
  return 0;
 }
/*____________________________________________________*/
MEXPORT_TRIGCALC int undefinedpart(term t, term arg, term *next, char *reason)
/* f(undefined) = undefined */
/* applied in automode to the whole current line */
{ if(equals(t,undefined))
     return 1;  /* don't cause a loop */
  if(contains_undefined(t))
     { *next = undefined;   /* losing info sometimes e.g. on  2*bounded_oscillations */
       HIGHLIGHT(*next);
       strcpy(reason,english(1371));  /* f(undefined)=undefined */
       return 0;
     }
  return 1;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int rationalizefraction(term t, term arg, term *next, char *reason)
/* called in auto mode instead of rationalizenum or rationalizedenom */
{ term num,denom;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  if(FUNCTOR(ARG(1,t)) != '/')
     return 1;
  if(get_mathmode() == AUTOMODE)
     { if(!rationalize_ok(t))  /* in inflims.c */
          return 1;
     }
  num = ARG(0,ARG(1,t));
  denom = ARG(1,ARG(1,t));    /* t = lim(h->a,num/denom)  */
  if(FUNCTOR(num) == '+' && ARITY(num)==2)
     { term b,c;
       b = ARG(0,num);
       c = ARG(1,num);
       if( (grf_aux(b) || grf_aux(c) ) &&  /* square root or root or ABS in one term */
           (
            (FUNCTOR(b) == '-' && FUNCTOR(c) != '-') ||  /* opposite signs */
            (FUNCTOR(c) == '-' && FUNCTOR(b) != '-')
           )
         )
          { err = rationalizenum(t,arg,next,reason);
            if(err)
               return 1;
            SetShowStepOperation(rationalizenum);
            return 0;
          }
     }
  if(FUNCTOR(denom) == '+' && ARITY(denom)==2)
     { term b,c;
       b = ARG(0,denom);
       c = ARG(1,denom);
       if( (grf_aux(b) || grf_aux(c) ) &&  /* square root or root or ABS in one term */
           (
            (FUNCTOR(b) == '-' && FUNCTOR(c) != '-') ||  /* opposite signs */
            (FUNCTOR(c) == '-' && FUNCTOR(b) != '-')
           )
         )
          { err = rationalizedenom(t,arg,next,reason);
            if(err)
               return 1;
            SetShowStepOperation(rationalizedenom);
            return 0;
          }
     }
  return 1;
}

/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int zerosqdenom(term t, term arg, term *next, char *reason)
{ term num,denom;
  int err;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(FUNCTOR(denom) != '^')
     return 1;
  if(!equals(ARG(1,denom),two))
     return 1;
  if(!ISZERO(ARG(0,denom)))
     return 1;
  if(NOTDEFINED(num))
     { errbuf(0, english(863));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(contains(num,LIMIT))
     { errbuf(0, english(864));
         /* First evaluate the numerator */
       return 1;
     }
  err = infer(lessthan(zero,num));
  if(!err)
     { *next = infinity;
       strcpy(reason, english(1959));
       /* lim a/u^2 = � if lim u = 0    and a > 0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       release(arithmetic);
       return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int zerosqdenom2(term t, term arg, term *next, char *reason)
{ term num,denom;
  int err;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(FUNCTOR(denom) != '^')
     return 1;
  if(!equals(ARG(1,denom),two))
     return 1;
  if(!ISZERO(ARG(0,denom)))
     return 1;
  if(NOTDEFINED(num))
     { errbuf(0, english(863));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(contains(num,LIMIT))
     { errbuf(0, english(864));
         /* First evaluate the numerator */
       return 1;
     }
  err = infer(lessthan(num,zero));
  if(!err)
     { *next = minusinfinity;
       strcpy(reason, english(1960));
       /* lim a/u^2 = -� if lim u = 0    and a < 0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       release(arithmetic);
       return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int zero2ndenom(term t, term arg, term *next, char *reason)
{ term num,denom;
  int err;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(FUNCTOR(denom) != '^')
     return 1;
  if(!iseven(ARG(1,denom)))
     return 1;
  if(!ISZERO(ARG(0,denom)))
     return 1;
  if(NOTDEFINED(num))
     { errbuf(0, english(863));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(contains(num,LIMIT))
     { errbuf(0, english(864));
         /* First evaluate the numerator */
       return 1;
     }
  err = infer(lessthan(zero,num));
  if(!err)
     { *next = infinity;
       strcpy(reason, english(1961));
       /* lim a/u^2� = � if lim u = 0    and a > 0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       release(arithmetic);
       return 0;
     }
  return 1;
}
/*_____________________________________________________________________*/
MEXPORT_TRIGCALC int zero2ndenom2(term t, term arg, term *next, char *reason)
{ term num,denom;
  int err;
  if(FUNCTOR(t) != '/')
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(FUNCTOR(denom) != '^')
     return 1;
  if(!iseven(ARG(1,denom)))
     return 1;
  if(!ISZERO(ARG(0,denom)))
     return 1;
  if(NOTDEFINED(num))
     { errbuf(0, english(863));
          /* numerator must be defined and nonzero. */
       return 1;
     }
  if(contains(num,LIMIT))
     { errbuf(0, english(864));
         /* First evaluate the numerator */
       return 1;
     }
  err = infer(lessthan(num,zero));
  if(!err)
     { *next = minusinfinity;
       strcpy(reason, english(1962));
       /* lim a/u^2� = -� if lim u = 0    and a < 0 */
       HIGHLIGHT(*next);
       release(polyvalop);
       release(arithmetic);
       return 0;
     }
  return 1;
}

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