Sindbad~EG File Manager

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

/* Limit operators */
/*
M. Beeson, for MathXpert
1.14.91 file created
3.12.99 last modified
1.2.99  changed '3' to '2' at line 140 in limsum
1.2.99  modified limsum at line 135 to fail in case limits of the sum contain the limit variable.
2.9.05 modified includes
*/

#include <string.h>
#include <assert.h>
#define TRIGCALC_DLL
#include "globals.h"
#include "ops.h"
#include "calc.h"
#include "prover.h"
#include "order.h"
#include "checkarg.h"
#include "cancel.h"
#include "factor.h"
#include "autosub.h"
#include "algaux.h"
#include "mplimits.h"
#include "graphstr.h"
#include "document.h"
#include "automode.h"  /* setlocus */
#include "mstring.h"     /* mstring  */
#include "deval.h"
#include "symbols.h"
#include "errbuf.h"
#include "pathtail.h"
#include "autosimp.h"
#include "trig.h"
#include "dispfunc.h"
#include "pvalaux.h"  /* iseven, isinteger */
#include "binders.h"
#include "psubst.h"
/*_________________________________________________________________*/
int poly2(term t, term x)
/* return 1 if t is equal to a polynomial, e.g. a product of polynomials
   in the variable x  */
{ unsigned short n;
  int i;
  if(mvpoly(t))
     return 1;
  if(! depends(t,x))
     return 1;   /* e.g. t = �7  */
  if(FUNCTOR(t) == '*' || FUNCTOR(t) == '+')
    { n = ARITY(t);
      for(i=0;i<n;i++)
        { if(!poly2(ARG(i,t),x))
             return 0;
        }
      return 1;
    }
  if(FRACTION(t) && INTEGERP(ARG(1,t)))
     return poly2(ARG(0,t),x);
  if(FUNCTOR(t) == '^')
    { if(!OBJECT(ARG(1,t)))
         return 0;
      if(TYPE(ARG(1,t))!=INTEGER && TYPE(ARG(1,t)) != BIGNUM)
         return 0;
      if(!poly2(ARG(0,t),x))
         return 0;
      return 1;
    }
  return 0;
}
/*____________________________________________________________________*/
MEXPORT_TRIGCALC int testlimit(term t, term arg, term *next, char *reason)
/*  experiment numerically */
{ term u,v,x;
  double p,q;
  int err;
  char buffer[81];
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  subst(zero,x,u,&v);
  if(!seminumerical(v))
     { errbuf(0,english(512));
          /* Can't evaluate numerically because */
       errbuf(1,english(513));
          /* a variable is present. */
       return 1;
     }
  subst(arg,x,u,&v);
  err = deval(v,&q);
  if(err)
     return 1;
  *next = make_double(q);
  HIGHLIGHT(*next);
  err = mstring(arg,buffer);
  if(err || strlen(buffer) > 17)
    { deval(arg,&p);
      mstring(make_double(p),buffer);
    }
  strcpy(reason,atom_string(x));
  strcat(reason," = ");
  strcat(reason,buffer);
  return 0;
}

/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limdif(term t, term arg, term *next, char *reason)
/* lim(u-v) = lim(u)-lim(v) */
{ term z;
  unsigned short n;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  z = LIMITAND(t);
  if(FUNCTOR(z) != '+')
     return 1;
  n = ARITY(z);
  if(FUNCTOR(ARG(n-1,z)) != '-')
     return 1;
  return limsum(t,arg,next,reason);
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limsum(term t, term arg, term *next, char *reason)
/* lim(u+v) = lim(u)+lim(v) */
{ int i,j,err,signflag;
  int count = 0;       /* count the undefined limits of summands */
  term indeterminate;  /* stash the last undefined limit of a summand */
  unsigned short n;
  term z,u,v,xtoa,temp,x;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  xtoa = ARG(0,t);
  x = ARG(0,xtoa);
  z = LIMITAND(t);
  if(FUNCTOR(z) == SUM)  /* work on an indexed sum */
     { term summand = ARG(0,z);
       term index = ARG(1,z);
       term lo = ARG(2,z);
       term hi = ARG(3,z);
       if( (INTEGERP(hi) || (!contains(hi,FUNCTOR(x)) && !infer(type(hi,INTEGER)))) &&
           (INTEGERP(lo) || (!contains(lo,FUNCTOR(x)) && !infer(type(lo,INTEGER))))
         )
          { *next = make_term(SUM,4);
            ARGREP(*next,0, ARITY(t) == 2 ? limit(xtoa,summand) : limit3(xtoa,ARG(1,t),summand));
            ARGREP(*next,1, index);
            ARGREP(*next,2,lo);
            ARGREP(*next,3,hi);
            goto out;
          }
     }
  if(FUNCTOR(z) != '+')
     return 1;
  n = ARITY(z);
  *next = make_term('+',n);
  for(i=0;i<n;++i)
    { signflag = 0;
      u = ARG(i,z);
      if(NEGATIVE(u))
         { u = ARG(0,u);
           signflag = 1;
         }
      v = ARITY(t)==2 ? limit(xtoa,u) : limit3(xtoa,ARG(1,t),u);
      err = limval(v,&temp);
      if(err)
         temp = undefined;
      if(NOTDEFINED(temp))
         { ++count;
           if(count == 1)
              {  /* stash the first indeterminate limit */
                if(ISINFINITE(temp) && signflag)
                   indeterminate = tnegate(temp);
                else
                   indeterminate = temp;
              }
           else if( !ISINFINITE(indeterminate)
                        /* example, sin(1/x) + sin(1/x^2)  as x->0 */
                    || (!signflag && !equals(temp,indeterminate))
                        /* one summand -> infinity, another -> minusinfinity */
                    || (signflag && equals(indeterminate,temp))
                  )
              { errbuf(0, english(514));
                /* Answer would be indeterminate  */
                if(contains(t,'/'))
                    errbuf(1, english(515));
                    /* Maybe common denominators would help */
                for(j=0;j<i;j++)
                   RELEASE(ARG(j,*next));
                RELEASE(*next);
                return 1;
              }
         }
      ARGREP(*next,i,signflag ? tnegate(v) : v);
    }
  out:
  release(commondenom);  /* all these may have been inhibited by divnumdenom */
  release(commondenomandsimp);
  release(commondenom2);
  release(commondenomandsimp2);
  release(polyvalop);
  release(lhopital);
  release(limlinear);
  release(pulloutnonzerolimit);
  release(limquotient);
  strcpy(reason,"lim(u+v)=lim u+lim v");
  if(signflag)
     reason[14] = reason[5] = '-';  /* lim(u-v)=lim u - lim v */
  HIGHLIGHT(*next);
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limsum3(term t, term arg, term *next, char *reason)
/* eliminate negative exponents in a sum in a limit, preparatory to
taking common denom when limit of a summand is infinity */
/* used only in automode after limsum has failed */
{ term u,mid,summand,temp;
  int i,err;
  int success = 0;
  unsigned short n = ARITY(t);
  unsigned short m;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != '+')
     return 1;
  m = ARITY(u);
  mid = make_term('+',m);
  for(i=0;i<m;i++)
     { summand = ARG(i,u);
       if(NEGATIVE(summand))
           summand = ARG(0,summand);
       err = eliminatenegexp(summand,zero,&temp,reason);
       if(err)
          ARGREP(mid,i,ARG(i,u));
       else if (NEGATIVE(summand))
          ARGREP(mid,i,tnegate(temp));
       else
          ARGREP(mid,i,temp);
       if(!err)
          ++success;
      }
  if(!success)
     return 1;
  *next = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
  return 0;
}
/*_________________________________________________________________*/
static unsigned short contains_ctrig(term t)
/* return CSC, SEC, TAN, or COT if t contains CSC, SEC, TAN, or COT;
   if t contains more than one it will be the first one encountered.
   Return 0 if it contains none of these functors
*/
{ unsigned short n,f,h;
  int i;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if(f == CSC || f == SEC || f == TAN || f == COT)
     return f;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { h = contains_ctrig(ARG(i,t));
       if(h)
          return h;
     }
  return 0;
}
/*_________________________________________________________________*/
static int rewrite_trig(unsigned short f, term u, term *ans)
/* f is CSC, SEC, COT, or TAN.  Rewrite one subterm of u
with functor f in terms of sin and cos and return the result in *ans.
Don't disturb the original term u.  If there are nested trig functions,
as in tan(tan x), it rewrites only the outermost one.  Return 0
for success, i.e. some subterm is rewritten.  Return 1 if there is no
subterm to rewrite.  In that case, *ans = t.
*/
{ unsigned short n;
  int i,flag,err;
  term v;
  if(ATOMIC(u))
     { *ans = u;
       return 1;
     }
  if(f == FUNCTOR(u))
     { v = ARG(0,u);
       switch(f)
          { case CSC:
               *ans = reciprocal(sin1(v));
               return 0;
            case SEC:
               *ans = reciprocal(cos1(v));
               return 0;
            case TAN:
               *ans = make_fraction(sin1(v),cos1(v));
               return 0;
            case COT:
               *ans = make_fraction(cos1(v),sin1(v));
               return 0;
            default:
               assert(0);
          }
      }
   if(FRACTION(u) && ONE(ARG(0,u)) && f == FUNCTOR(ARG(1,u)))
      { v = ARG(0,ARG(1,u));
        switch(f)
           { case CSC:
                *ans = sin1(v);
                return 0;
             case SEC:
                *ans = cos1(v);
                return 0;
             case TAN:
                *ans = make_fraction(cos1(v),sin1(v));
                return 0;
             case COT:
                *ans = make_fraction(sin1(v),cos1(v));
                return 0;
           }
      }
   n = ARITY(u);
   *ans = make_term(FUNCTOR(u),n);
   flag = 0;
   for(i=0;i<n;i++)
      { if(!flag)
           { err = rewrite_trig(f,ARG(i,u),ARGPTR(*ans)+i);
             if(!err)
                flag = 1;
           }
        else
           ARGREP(*ans,i,ARG(i,u));
      }
   return flag ? 0 : 1;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limsum4(term t, term arg, term *next, char *reason)
/*  Applies to a limit of a sum.  Rewrites ONE trig function in
the limitand in terms of sin and cos, so that common denoms can
be taken.  Examples:  lim(x->0, 1/x - csc x),
                      lim(x->0, csc x - cot x).
Used in automode after limsum has failed, but BEFORE common denoms.
It only rewrites one function at a time, as you would have to do
in menu mode or by term selection, so the second example will need
two steps. This operator is not used in menu mode
or term selection mode, where the trig function in question can be
directly selected, or the operator chosen from the trig menu.
*/
{ term u,mid;
  unsigned short f;
  int err;
  unsigned short n = ARITY(t);
  unsigned short path[MAXTAIL];
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != '+')
     return 1;
  /* First see if it will apply */
  f = contains_ctrig(u);
  if(!f)
     return 1;
  err = rewrite_trig(f,u,&mid);  /* f is the functor to be rewritten */
  if(err)
     return 1;
  path[0] = LIMIT;
  path[1] = n;
  path_to_difference(u,mid,path+2,1);
  set_pathtail(path);
  *next = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
  switch(f)
     { case TAN:
          strcpy(reason, "tan x = (sin x)/cos x");
          SetShowStepOperation(tanrule);
          break;
       case COT:
          strcpy(reason, "cot x = (cos x)/sin x");
          SetShowStepOperation(cottosincos);
          break;
       case SEC:
          strcpy(reason,"sec x = 1 / cos x");
          SetShowStepOperation(secrule);
          break;
       case CSC:
          strcpy(reason,"csc x = 1 / sin x");
          SetShowStepOperation(cscrule);
          break;
     }
  return 0;
}

/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limsum1(term t, term arg, term *next, char *reason)
/* factor denominators in a sum in a limit, preparatory to
taking common denom when limit of a summand is infinity */
/* used only in automode after limsum has failed */
{ term u,mid,summand;
  int i,err;
  unsigned short n = ARITY(t);
  unsigned short m;
  unsigned short path[32];
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != '+')
     return 1;
  err = factordenominator(u,zero,&mid,reason);
  if(err)
     return 1;
  /* Now we have to protect the factored forms lest they be
     multiplied out again.  Remember, comdenomflag is off!  */
  m = ARITY(u);
  for(i=0;i<m;i++)
     { summand = ARG(i,mid);
       if(NEGATIVE(summand))
          summand = ARG(0,summand);
       if(FRACTION(summand) && FUNCTOR(ARG(1,summand)) == '*')
          PROTECT(ARG(1,summand));
     }
  /* factordenominator has already set a pathtail, and has called
  SetShowStepOperation, but the path now needs adjusting */
  path[0] = LIMIT;
  path[1] = n;
  path[2] = 0;
  pathncopy(path+2,30,get_pathtail());
  set_pathtail(path);
  *next = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);;
  return 0;
}

/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limsum2(term t, term arg, term *next, char *reason)
/* take common denom when limit of a summand is infinity */
/* used only in automode after limsum has failed */
{ term u,mid;
  int err,statusflag;
  unsigned short path[5];
  unsigned short n = ARITY(t);
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  if(FUNCTOR(u) != '+')
     return 1;
  statusflag = status(commondenomandsimp);
  if(statusflag == WELLKNOWN)
     err = commondenomandsimp(u,zero,&mid,reason);
  else
     err = commondenom(u,zero,&mid,reason);
  if(err)
     return 1;
  path[0] = LIMIT;
  path[1] = n;
  path[2] = 0;
  set_pathtail(path);
  SetShowStepOperation(statusflag == WELLKNOWN ? commondenomandsimp : commondenom);
  *next = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);;
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limminus(term t, term arg, term *next, char *reason)
/* lim(-u) = - lim u */
{ term u,v;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  v = LIMITAND(t);
  if(FUNCTOR(v) != '-')
     return 1;
  u = ARG(0,v);
  tneg(ARITY(t)==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u),next);
  HIGHLIGHT(*next);
  strcpy(reason,"lim(-u) = - lim u");
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limconst(term t, term arg, term *next, char *reason)
/* lim(x->a,c)=c (c const) */
{ if(FUNCTOR(t) != LIMIT)
     return 1;
  if(depends(LIMITAND(t),ARG(0,ARG(0,t))))
     return 1;
  *next = LIMITAND(t);
  HIGHLIGHT(*next);
  strcpy(reason, english(2162));
    /* lim(x�a,c) = c       (c constant) */
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limident(term t, term arg, term *next, char *reason)
/* lim(x->a,x)=a */
{ if(FUNCTOR(t) != LIMIT)
     return 1;
  if(!equals(ARG(0,ARG(0,t)),LIMITAND(t)))
     return 1;
  *next = ARG(1,ARG(0,t));
  HIGHLIGHT(*next);
  strcpy(reason,"$lim(x�a,x)=a$");
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limlinear(term t, term arg, term *next, char *reason)
/* lim(cu)=c lim u (c const) */
{ term z,x,c,d,w,u,v,newlim;
  unsigned short n = ARITY(t);
  unsigned short f;
  int signflag = 1;
  int err;
  if(FUNCTOR(t) == '*' && n == 2  &&
     POSNUMBER(ARG(0,t)) &&
     FUNCTOR(ARG(1,t)) == LIMIT
    )
     { /* work on 2 lim(3u) producing 6 lim(u) */
       term temp, temp2;
       int i;
       err = limlinear(ARG(1,t),arg,&temp,reason);
       if(err || FUNCTOR(temp) != '*')
          return 1;
       temp2 = make_term('*',ARITY(temp));
       ARGREP(temp2,0,ARG(0,temp));
       for(i=1;i<ARITY(temp);i++)
          ARGREP(temp2,i,ARG((unsigned short)(i-1),temp));
       err = value(temp2,&v);
       if(err != 0 && err != 2)
          *next = product(ARG(0,t),temp);
       else
          *next = product(v,ARG((unsigned short)(n-1),t));
       HIGHLIGHT(*next);
       return 0;
     }
  if(FUNCTOR(t) != LIMIT)
     return 1;
  z = LIMITAND(t);
  if(NEGATIVE(z))
     { z = ARG(0,z);
       signflag = -1;
     }
  x = ARG(0,ARG(0,t));
  if(!depends(z,x))
      {  /* entire expression is constant */
         if(!ATOMIC(z) && !(ARITY(z)==1 && ATOMIC(ARG(0,z))))
            { char buffer[128];
              strcpy(buffer,english(516));
                 /* The entire expression inside `lim' is independent of  */
              strcat(buffer,atom_string(x));
              errbuf(0,buffer);
              errbuf(1, english(977));
                 /* Use \"lim(t�a,c) = c (c constant)\" instead. */
             /*  Formerly this went to comment_buffer and limconst was
                 applied.  But this generates a weird result on
                 lim(x->0, 3x) + lim(x->0,3), where the second attempted
                 application uses this clause and generates an
                 inappropriate comment.  */
            }
         return 1;
      }
  f = FUNCTOR(z);
  switch(f)
     { case '/':
          twoparts(ARG(1,z),x,&c,&v);
          twoparts(ARG(0,z),x,&d,&w);
          if(ONE(c) && ONE(d))
              return 1;
          u = signedfraction(w,v);
          newlim = n==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
          c = signedfraction(d,c);
          break;
       case '*':
          twoparts(z,x,&c,&u);
          if(ONE(c))
             return 1;
          newlim = n==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
          break;
       default:
          return 1;
     }
  if(!(OBJECT(c) && !ZERO(c)))
     { /* be careful not to pull out a constant like (a^0 -1) leaving
          an undefined limit behind */
       err = infer(nonzero(c));
       if(err)
          { err = limval(newlim,&w);
            if(err || NOTDEFINED(w))
                { errbuf(0, english(1395));
                  /* Constant must be nonzero, or remaining limit defined. */
                  return 1;
                }
          }
     }
  if(signflag == -1)
     c = tnegate(c);
  if(ONE(c))
     return 1;
  HIGHLIGHT(c);
  *next = signedproduct(c,newlim);
  strcpy(reason,"lim(cu) = c lim u");
  return 0;
}
/*_________________________________________________________________*/
static int ok_product(term a, term b, term *ans)
/* a and b have one of the following values.  Return 1 if their product
can be determined, 0 if not.  If 1 is returned, put the product in *ans.
The values in question are:
    infinity,minusinfinity,bounded_oscillations, unbounded_oscillations,
    undefined.
*/
{ unsigned short aa = FUNCTOR(a);
  unsigned short bb = FUNCTOR(b);
  if(aa == UNDEFINED || bb == UNDEFINED)
     return 0;
  switch(aa)
     { case INFINITY:
          switch(bb)
             { case INFINITY:  *ans = infinity;
                               return 1;
               case '-'     :  *ans = minusinfinity;
                               return 1;
               case UNBOUNDED_OSCILLATIONS:  *ans = unbounded_oscillations;
                                             return 1;
               case BOUNDED_OSCILLATIONS:    *ans = unbounded_oscillations;
                                             return 1;
               default:        assert(0);
             }
       case '-' :
          switch(bb)
             { case INFINITY:  *ans = minusinfinity;
                               return 1;
               case '-'     :  *ans = infinity;
                               return 1;
               case UNBOUNDED_OSCILLATIONS:  *ans = unbounded_oscillations;
                                             return 1;
               case BOUNDED_OSCILLATIONS:    *ans = unbounded_oscillations;
                                             return 1;
               default:        assert(0);
             }
       case UNBOUNDED_OSCILLATIONS:
          switch(bb)
             { case INFINITY:  *ans = unbounded_oscillations;
                               return 1;
               case '-'     :  *ans = unbounded_oscillations;
                               return 1;
               case UNBOUNDED_OSCILLATIONS:  *ans = unbounded_oscillations;
                                             return 1;
               case BOUNDED_OSCILLATIONS:    *ans = unbounded_oscillations;
                                             return 1;
               default:        assert(0);
             }
       case BOUNDED_OSCILLATIONS:
          switch(bb)
             { case INFINITY:  *ans = unbounded_oscillations;
                               return 1;
               case '-'     :  *ans = unbounded_oscillations;
                               return 1;
               default:        return 0;
             }
       default:    assert(0);
     }
  return 0;  /* avoid a warning message */
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limprod(term t, term arg, term *next, char *reason)
/* lim(uv)= lim(u) lim(v) */
{ int i,err;
  unsigned short n,m;
  int count = 0;   /* count the undefined limits of factors */
  int zeroflag = 0;  /* set if there is a factor with limit zero */
  term z,u,v,temp,indeterminate;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  m = ARITY(t);
  z = LIMITAND(t);
  if(FUNCTOR(z) != '*')
     return 1;
  n = ARITY(z);
  *next = make_term('*',n);
  for(i=0;i<n;++i)
     { u = ARG(i,z);
       v = m==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
       err = limval(v,&temp);
       if(err)
          temp = undefined;
       if(ZERO(temp))
          zeroflag = 1;
       if( (ZERO(temp) && count) ||
           (zeroflag && NOTDEFINED(temp) && !equals(temp,bounded_oscillations))
         )
          { errbuf(0,english(879));
              /* The result would have the form zero times undefined. */
            return 1;
          }
       if(NOTDEFINED(temp))
          { ++count;
            if(count == 1)
               indeterminate = temp;
            else if(!ok_product(indeterminate,temp,&indeterminate))
               { errbuf(0, english(880));
                   /* The result would be indeterminate */
                 return 1;
               }
          }
       ARGREP(*next,i,v);
     }
  if(count && zeroflag)
     {  /* there was at least one indeterminate factor and a zero */
        errbuf(0, english(1969));
        /* $lim uv = lim u lim v$ can fail if lim u = 0 and lim v is undefined. */
        return 1;  /* if the indeterminate factor was bounded_oscillations,
                      squeezetheorem will get it later */
     }
  strcpy(reason,"lim(uv)=lim u lim v");
  HIGHLIGHT(*next);
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limpower(term t, term arg, term *next, char *reason)
/* lim u� = (lim u)� */
/* This rule is valid when lim u exists or is infinite, or when n is odd,
or when u is nonnegative.  Indeed it's also valid if the limit of u
oscillates; the only thing that can go wrong is if u has values on
different branches of the n-th root, as in the case u = abs(x)/x.
However, since students don't work with bounded_oscillation as a value,
you can't use this operation on lim(x->infinity, cos^2 x).
*/
{ term u,n,w,mid,temp,h;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  w = LIMITAND(t);
  if(FUNCTOR(w) != '^')
     return 1;
  u = ARG(0,w);
  n = ARG(1,w);   /* the exponent */
  h = ARG(0,ARG(0,t));  /* the bound variable */
  if(depends(n,h))
     { errbuf(0, english(517));
           /* Exponent isn't constant */
       errbuf(1, english(518));
           /* so that operator can't be used. */
       return 1;
     }
  mid = ARITY(t)==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
  if(isinteger(n) && isodd(n))
     goto out;  /* no need to compute the limval of mid */
  if(NEGATIVE(n) && isinteger(ARG(0,n)) && isodd(ARG(0,n)))
     goto out;
  if(RATIONALP(n) && ISODD(ARG(0,n)) && ISODD(ARG(1,n)))
     goto out;
  if(obviously_nonnegative(w))
     goto out;
  err = limval(mid,&temp);
  if(!err)
     { if(equals(temp,undefined))
          { errbuf(0, english(1963));
            /* $lim u� = (lim u)�$ requires lim $u$ to be defined, infinite, or oscillatory, */
            errbuf(1, english(1967));
            /* or when u is nonnegative or nonpositive. */
            errbuf(2, english(1965));  /* That is not the case here. */
            return 1;
          }
       goto out;
     }
   /* Now limval(mid) could not be computed. */
  if(ZERO(temp))
     { err = check(nonzero(n));
       if(err)
          { errbuf(0, english(519));
              /* Exponent is zero.  Simplify it directly. */
            return 1;
          }
     }
  /* Now try to infer that the limitand is nonnegative */
  fillbinders(t);
  err = infer(le(zero,u));
  releasebinders();
  if(!err)
     goto out;
  fillbinders(t);
  err = infer(le(u,zero));
  releasebinders();
  if(!err)
     goto out;
  errbuf(0, english(1963));
  errbuf(1, english(1967));
  errbuf(2, english(1964));  /* MathXpert cannot verify either hypothesis */
  return 1;  /* final failure */
  out:
     *next = make_power(mid,n);
     HIGHLIGHT(*next);
     strcpy(reason,"lim u^n = (lim u)^n");
     return 0;
}

/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limexponent(term t, term arg, term *next, char *reason)
/* lim u^v = (lim u) ^ (lim v) */
/* But,  1^infinity and 1^-infinity must not be created,
   and 0^0 must not be created, and 0^infinity and 0^-infinity
   must not be created */

{ term u,v,base,power,w,x;
  int err;
  unsigned short n;
  int flag;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  n = ARITY(t);
  w = LIMITAND(t);
  if(FUNCTOR(w) != '^')
     return 1;
  u = ARG(0,w);
  v = ARG(1,w);
  x = ARG(0,ARG(0,t));
  flag = depends(u,x);
  if(!flag)
     base = u;
  else
     base =  n==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
  power =  n==2 ? limit(ARG(0,t),v) :  limit3(ARG(0,t),ARG(1,t),v);
  if(flag)
     { term baseval,powerval;
       err = limval(base,&baseval);
       if(err)
          { errbuf(0, english(1492));
            /* Cannot calculate the limit of the base. */
            return 1;
          }
       if(ZERO(baseval))
          { err = limval(power,&powerval);
            if(err)
               { errbuf(0, english(1493));
                 /* Cannot calculate the limit of the exponent/ */
                 return 1;
               }
            if(ZERO(powerval))
               { errbuf(0, english(1494));
                 /* That would create 0 to the power 0, which is undefined. */

                 return 1;
               }
            if(NOTDEFINED(powerval))
               { errbuf(0, english(1495));
                 /* That would create 0 to an undefined power, which is undefined. */
                 errbuf(1, english(1495));
                 /* However, that doesn't prove your limit is undefined. */
                 return 1;
               }
          }
       else if(equals(baseval,infinity))
          { err = limval(power,&powerval);
            if(err)
               { errbuf(0, english(1493));
                 /* Cannot calculate the limit of the exponent/ */
                 return 1;
               }
            if(ZERO(powerval))
               { errbuf(0, english(1499));
                 /* That would create infinity raised to the power 0. */
                 return 1;
               }
            if(NOTDEFINED(powerval))
               { if(!equals(powerval,infinity) && !equals(powerval,minusinfinity))
                    { errbuf(0, english(1500));
                      /* Limit of exponent is undefined. */
                      return 1;
                    }
                 /* actually we could work with infinity ^ bounded_oscillations
                    and infinity^unbounded_oscillations if students
                    had symbols for those ideas. */
               }
          }
       else if(NOTDEFINED(baseval))
          return 1;
       else if(ONE(baseval))
          { err = limval(power,&powerval);
            if(err)
               { errbuf(0, english(1493));
                 /* Cannot calculate the limit of the exponent/ */
                 return 1;
               }
            if(NOTDEFINED(powerval))
               { errbuf(0, english(1497));
                 /* That would create 1 raised to an undefined or infinite power. */
                 errbuf(1, english(1498));
                 /* The limit cannot be evaluated this way. */
                 return 1;   /* 1^infinity or 1^(-infinity) or 1^undefined
                           is undefined; this comes up in e.g. lim(1+u)^(1/u)
                           as u->0, which is actually e.  */
               }
          }
     }
  *next = make_power(base,power);
  HIGHLIGHT(*next);
  strcpy(reason,"lim u^v=(lim u)^(lim v)");
  /* The last pair of parens don't print, so it comes out to 21 characters */
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limexponent2(term t, term arg, term *next, char *reason)
/* lim c^v = c ^ (lim v), c constant > 0 */
{ term u,v,base, power,w;
  unsigned short n;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  n = ARITY(t);
  w = LIMITAND(t);
  if(FUNCTOR(w) != '^')
     return 1;
  u = ARG(0,w);
  v = ARG(1,w);
  if(depends(u,ARG(0,ARG(0,t))))
     { errbuf(0, english(1272)); /* Base is not constant. */
       return 1;
     }
  base = u;
  power =  n==2 ? limit(ARG(0,t),v) :  limit3(ARG(0,t),ARG(1,t),v);
  *next = make_power(base,power);
  HIGHLIGHT(*next);
  strcpy(reason, english(2163));
   /* lim c^v=c^(lim v)      (c constant > 0) */
  return 0;
}

/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limoddroot(term t, term arg, term *next, char *reason)
/* lim ��u)=��(lim u)       if n is odd */
{ term u,n,w;
  int err;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  w = LIMITAND(t);
  if(FUNCTOR(w) != ROOT)
     return 1;
  n = ARG(0,w);
  u = ARG(1,w);
  err = check(odd(n));
  if(err)
     { errbuf(0,english(522));
          /* Index of root is not odd */
       errbuf(1,english(521));
          /* so that operator can't be used. */
       return 1;
     }
  if(ARITY(t)==2)
       *next = make_root(n,limit(ARG(0,t),u));
  else
       *next = make_root(n,limit3(ARG(0,t),ARG(1,t),u));
  HIGHLIGHT(*next);
  strcpy(reason, english(523));
      /* lim ��u = ��(lim u)  if n is odd */
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limevenroot(term t, term arg, term *next, char *reason)
/* lim ��u = ��(lim u)   if lim u > 0 */
{ int err;
  term u,n,w,h;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  h = ARG(0,ARG(0,t));  /* limit variable */
  w = LIMITAND(t);
  if(FUNCTOR(w) != ROOT)
     return 1;
  n = ARG(0,w);
  u = ARG(1,w);
  if(contains(n,FUNCTOR(h)))
     { errbuf(0, english(878));
          /* Index of root must be an integer */
          /* Hopefully you can't enter a term like this anyway */
       return 1;
     }
  err = infer(odd(n));
  if(!err)
     return limoddroot(t,arg,next,reason);
  err = check(positive(limit(ARG(0,t),u)));
  if(err)
     { errbuf(0, english(524));
          /* Limit under �� would not be positive, */
       errbuf(1, english(521));
          /* so that operator can't be used */
       return 1;
     }
  *next = make_root(n,(ARITY(t)==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u)));
  HIGHLIGHT(*next);
  strcpy(reason, english(525));
     /* lim ��u = ��(lim u)  if lim u > 0 */
  return 0;
}

/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limsqrt(term t, term arg, term *next, char *reason)
/* lim �u)=�(lim u) if lim u>0 */
{ int err;
  term u,w,p,q,mid;
  unsigned short n;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  n = ARITY(t);
  w = LIMITAND(t);
  if(FUNCTOR(w) != SQRT)
     return 1;
  u = ARG(0,w);
  mid = n==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
  err = limval(t,&p);  /* can we calculate this limit? */
  if(!err) /* yes */
     { if(equals(p,undefined))
          { limval(mid,&q);
            err = check(positive(q));
            if(err)
              { errbuf(0, english(526));
                   /* Limit under � would not be positive */
                errbuf(1, english(521));
                   /* so that operator can't be used. */
                return 1;
              }
          }
     }
  else
     { q =lessthan(zero,mid);
       SETPROVISIONAL(q);
       assume(q);
     }
  *next = sqrt1(mid);
  HIGHLIGHT(*next);
  strcpy(reason, english(527));
     /* lim �u = �(lim u)    if lim u > 0 */
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_TRIGCALC int limpoly(term t, term arg, term *next, char *reason)
/* lim(x->a,f(x))= f(a)      (polynomial f) */
{ int err;
  term a,u,x;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = LIMITAND(t);
  x = ARG(0,ARG(0,t));
  a = ARG(1,ARG(0,t));
  if(!poly2(u,x))
     return 1;
  if(NOTDEFINED(a))
     { err = limval(t,next);
       if(err)
          return 1;
       strcpy(reason, english(528));   /* limit of polynomial */
     }
  else
     { psubst(a,x,u,next);
       strcpy(reason, english(529));
          /* lim(x�a,f(x))= f(a)      (polynomial f) */
     }
  HIGHLIGHT(*next);
  return 0;
}
/*__________________________________________________________________________*/
MEXPORT_TRIGCALC int limapartandfactor(term t, term arg, term *next, char *reason)
/* lim (ab+ac+d)/q = lim a(b+c)/q + lim d/q */
/* To find the derivative of sin x
direct from the definition of derivative, we need to get the limit of
(sin x cos h + cos x sin h - sin x)/h  =
(sin x)(cos h - 1)/h + (cos x sin h)/h  */

/* In auto mode, will work only if a can be found as a non-product term; that
suffices for the example above and similar ones.  In menu mode,
user is asked to enter a.   This operator will ONLY work on a limit term, by
working on the limitand, so it can be associated to LIMIT in auto mode,
and can refuse to work if the resulting limits would be indeterminate. */

{ term p,u,v,ans,temp;
  unsigned short n,m;
  int i,err;
  unsigned short flag;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  u = ARITY(t)==2 ? ARG(1,t) : ARG(2,t);  /* the limitand */
  err = apartandfactor(u,arg,&temp,reason);
  if(err)
     return 1;
  /* don't use it if two of the limits of the summands are undefined */
  flag = 0;
  assert(FUNCTOR(temp)== '+');
  n = ARITY(temp);
  for(i=0;i<n;i++)
     { v = ARG(i,temp);
       p = ARITY(t) == 2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
       err = limval(p,&ans);
       if(err)
          { if(get_mathmode() == MENUMODE)
               strcpy(reason, english(1059));
                  /* Resulting limits would be too hard for MathXpert. */
            return 1;
          }
       if(NOTDEFINED(ans))
          { if(flag == FUNCTOR(ans) && equals(ans,infinity))
               continue;
            if(flag == FUNCTOR(ans) && equals(ans,minusinfinity))
               continue;
            if(flag)
               { if(get_mathmode() == MENUMODE)
                    strcpy(reason, english(1058));
                       /* Resulting sum of limits would be indeterminate */
                    return 1;  /* this is the second undefined summand */
               }
            flag = FUNCTOR(ans);
               /* this is only the first undefined summand */
          }
     }
  m = ARITY(temp);
  *next = make_term('+', m);
  for(i=0;i<m;i++)
     { v = ARITY(t) == 2 ? limit(ARG(0,t),ARG(i,temp)) : limit3(ARG(0,t),ARG(1,t),ARG(i,temp));
       ARGREP(*next,i,v);
     }
  HIGHLIGHT(*next);
  return 0;
}
/*_______________________________________________________________*/
MEXPORT_TRIGCALC int limvalop(term t, term arg, term *next, char *reason)
{ int err;
  if(FUNCTOR(t)!= LIMIT)
     return 1;
  err = limval(t,next);
  if(err)
     { errbuf(0,english(1944));
        /* MathXpert cannot calculate that limit. */
       return 1;
     }
  strcpy(reason, english(1178));  /* evaluate limit */
  HIGHLIGHT(*next);
  return 0;
}
/*_________________________________________________________________*/
MEXPORT_TRIGCALC int limabs(term t, term arg, term *next, char *reason)
/* lim |u|= |lim u| */
{ term u,w,mid;
  unsigned short n;
  if(FUNCTOR(t) != LIMIT)
     return 1;
  n = ARITY(t);
  w = LIMITAND(t);
  if(FUNCTOR(w) != ABS)
     return 1;
  u = ARG(0,w);
  mid = n==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
  *next = abs1(mid);
  HIGHLIGHT(*next);
  strcpy(reason, "lim |u| = |lim u|");
  return 0;
}

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