Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/trigcalc/
Upload File :
Current File : /usr/home/beeson/MathXpert/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
3.18.23 initialized signflag in limsum
10.22.23 removed OEM symbols
2.18.23  added missing braces around line 1100
*/

#include <string.h>
#include <assert.h>

#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 "mpdoc.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 = \sqrt 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;
}
/*____________________________________________________________________*/
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;
}

/*_________________________________________________________________*/
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);
}
/*_________________________________________________________________*/
int limsum(term t, term arg, term *next, char *reason)
/* lim(u+v) = lim(u)+lim(v) */
{ int i,j,err,signflag=0;
  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;
}
/*_________________________________________________________________*/
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;
}
/*_________________________________________________________________*/
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;
}

/*_________________________________________________________________*/
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;
}

/*_________________________________________________________________*/
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;
}
/*_________________________________________________________________*/
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;
}
/*_________________________________________________________________*/
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) */
    /* Note the ability to mix displayed and not-displayed formulas,
       new in Feb. 2024, and only good with SVG display.
    */
  return 0;
}
/*_________________________________________________________________*/
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;
}
/*_________________________________________________________________*/
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 INFINITYFUNCTOR:
          switch(bb)
             { case INFINITYFUNCTOR:  *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 INFINITYFUNCTOR:  *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 INFINITYFUNCTOR:  *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 INFINITYFUNCTOR:  *ans = unbounded_oscillations;
                               return 1;
               case '-'     :  *ans = unbounded_oscillations;
                               return 1;
               default:        return 0;
             }
       default:    assert(0);
     }
  return 0;  /* avoid a warning message */
}
/*_________________________________________________________________*/
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;
}
/*_________________________________________________________________*/
int limpower(term t, term arg, term *next, char *reason)
/* lim u^n= (lim u)^n */
/* 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^n = (lim u)^n$ 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 = check1(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;
}

/*_________________________________________________________________*/
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(t->a, u^v)=(lim(t->a, u))^(lim (t->a,v))$$");
  /* The last pair of parens don't print, so it comes out to 21 characters */
  return 0;
}
/*_________________________________________________________________*/
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, "$lim c^v = c^(\\lim v)$");
  return 0;
}

/*_________________________________________________________________*/
int limoddroot(term t, term arg, term *next, char *reason)
/* lim ^n\sqrt u)= ^n\sqrt (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 = check1(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 ^n\sqrt u = ^n\sqrt (lim u)  if n is odd */
  return 0;
}
/*_________________________________________________________________*/
int limevenroot(term t, term arg, term *next, char *reason)
/* lim ^n\sqrt u = ^n\sqrt (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 = check1(positive(limit(ARG(0,t),u)));
  if(err)
     { errbuf(0, english(524));
          /* Limit under ^n\sqrt  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 ^n\sqrt u = ^n\sqrt (lim u)  if lim u > 0 */
  return 0;
}

/*_________________________________________________________________*/
int limsqrt(term t, term arg, term *next, char *reason)
/* lim \sqrt u)=\sqrt (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 = check1(positive(q));
            if(err)
              { errbuf(0, english(526));
                   /* Limit under \sqrt  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 \\sqrt u = \\sqrt (lim u)    if lim u > 0 */
  return 0;
}
/*__________________________________________________________________*/
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;
}
/*__________________________________________________________________________*/
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;
}
/*_______________________________________________________________*/
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;
}
/*_________________________________________________________________*/
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) != ABSFUNCTOR)
     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