Sindbad~EG File Manager

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

/* binomialtheorem operator for MathXpert
Michael Beeson
Original date 11.21.90
modified 1.20.99
1.11.00 modified remove_zero_powers
7.20.05  made binomialtheorem and plainbinomialtheorem fail on exponent 0.
*/

#define ALGEBRA_DLL
#include <string.h>
#include <assert.h>
#include "globals.h"
#include "ops.h"
#include "trig.h"
#include "simpprod.h"
#include "pvalaux.h"  /* for square2 */
#include "symbols.h"
#include "errbuf.h"
#include "autosimp.h" /* SetShowStepOperation */
#include "psubst.h"

static term remove_zero_powers(term t);
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int cubeofsum(term t, term arg, term *next, char *reason)
/*  (a+b)^3 = a^3 + 3a^2b + 3ab^2 + b^3 */
{ if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != '+')
     return 1;
  if(!equals(ARG(1,t),three))
     return 1;
  return binomialtheorem(t,arg,next,reason);
  /* it sets the reason correctly when it calls SetShowStepOperation */
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int cubeofdif(term t, term arg, term *next, char *reason)
/*  (a-b)^3 = a^3 - 3a^2b + 3ab^2 - b^3 */
{ term u;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  if(FUNCTOR(u) != '+')
     return 1;
  if(!NEGATIVE(ARG(ARITY(u)-1,u)))
     return 1;
  if(!equals(ARG(1,t),three))
     return 1;
  return binomialtheorem(t,arg,next,reason);
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int binomialtheorem(term t, term arg, term *next, char *reason)
/*  expand a power by the binomial theorem */
/*  use sigma notation for powers more than 4, but write them
    out directly for powers 2, 3 and 4.  Also write them out directly
    for powers up to 8 when doing integrals.
*/

{ term u,n,a,b,index,v;
  unsigned long k;  /* the exponent */
  int sign = 1;
  if(FUNCTOR(t) != '^')
     return 1;
  u = ARG(0,t);
  n = ARG(1,t);
  if(FUNCTOR(u) != '+')
     return 1;
  if(ARITY(u) > 2)  /* (a+b+c)�  */
     { a = u;
       SETFUNCTOR(a,'+',(unsigned short)(ARITY(u)-1));
       b = ARG(ARITY(u)-1,u);
       v = make_term('+',2);
       ARGREP(v,0,a);
       ARGREP(v,1,b);  /* v = sum(a,b) will flatten the sum again uselessly */
       return binomialtheorem(make_power(v,n),arg,next,reason);
     }
  if(OBJECT(n) && TYPE(n)==BIGNUM)
     { errbuf(0, english(426));
          /* Sorry, the exponent has to be less than two billion. */
       return 1;
     }
  if(! ISINTEGER(n))
     { errbuf(0, english(976));
          /* Exponent must be an integer */
       return 1;  /* can only handle integer exponent */
     }
  k = INTDATA(n);
  a = ARG(0,u);
  b = ARG(1,u);
  if(NEGATIVE(b))
     { sign = -1;
       b = ARG(0,b);
     }
  if(k == 0)
     return 1; 
  if(k <= 5)
     /* don't change the 5 unless you soup up smallbinomial to handle it */
     { smallbinomial(t,next);
       strcpy(reason, k == 2 ? "(a+b)^2 = a^2+2ab+b^2" : english(427)); /* binomial theorem */
       switch(k)
          { case 2:
               if(sign == 1)
                  { strcpy(reason,"(a+b)^2=a^2+2ab+b^2");
                    SetShowStepOperation(squareofsum);
                  }
               else
                  { strcpy(reason,"(a-b)^2=a^2+2ab+b^2");
                    SetShowStepOperation(squareofdif);
                  }
               break;
            case 3:
               if(sign == 1)
                  { strcpy(reason,"(a+b)^3=a^3+3a^2b+3ab^2+b^3");
                    SetShowStepOperation(cubeofsum);
                  }
               else
                  { strcpy(reason,"(a-b)^3=a^3-3a^2b+3ab^2-b^3");
                    SetShowStepOperation(cubeofdif);
                  }
               break;
            case 4:  /* fall through */
            case 5:
               SetShowStepOperation(plainbinomialtheorem);
               break;
          }
       return 0;
     }
  /*  Now k > 4, so use binomial coefficients */
  *next = make_term(SUM,4);
  index = index_variable(t);
  if(ONE(a))
     u = product(make_binomial(n,index),make_power(b,index));
  else if ONE(b)
     u = product(make_binomial(n,index),make_power(a,sum(n,tnegate(index))));
  else
     { u = make_term('*',3);
       ARGREP(u,1,make_power(a,sum(n,tnegate(index))));   /*  a^(n-i)  */
       ARGREP(u,2,make_power(b,index));                   /* b^i */
       ARGREP(u,0,make_binomial(n,index));
     }
  if(sign == -1)
     u = product(make_power(minusone,index),u);
  ARGREP(*next,0,u);
  ARGREP(*next,3,n);
  ARGREP(*next,2,zero);
  ARGREP(*next,1,index);
  HIGHLIGHT(*next);
  strcpy(reason, english(427));   /*  binomial theorem */
  return 0;
}
/*______________________________________________________________*/
MEXPORT_ALGEBRA int plainbinomialtheorem(term t, term arg, term *next,char *reason)
/* expand t by the binomial theorem, without using sigma notation
and binomial coefficients, returning in *ans the standard polynomial
form of the answer. */
{ int i,err;
  term a,b,d;
  unsigned short k;
  bignum c,w,q,r,z1,z2;
  term u,temp;
  long clong;
  if(FUNCTOR(t) != '^' || FUNCTOR(ARG(0,t)) != '+')
     return 1;
  if(!INTEGERP(ARG(1,t)))
     { errbuf(0,english(976));
          /* Exponent must be an integer */
       return 1;
     }
  if(!ISINTEGER(ARG(1,t)) || INTDATA(ARG(1,t)) > 300)
     { if(ARITY(t) > 2)
          { if(INTDATA(ARG(1,t)) > 100)
               { errbuf(0, english(975)); 
                 /* Exponent is too large. */
                 return 1;
               }
          }
       else  /* if(ARITY(t) == 2) */
          { if(
               (ONE(ARG(1,ARG(0,t))) && ISATOM(ARG(0,ARG(0,t)))) ||
               (ONE(ARG(0,ARG(0,t))) && ISATOM(ARG(1,ARG(0,t)))) 
              )
               { if(INTDATA(ARG(1,t)) > 800)
                    { errbuf(0, english(975));
                      /* we can do (x+1)^800 but not (x+1)^850 as of January, 1999 */
                      return 1;
                    }
               }
            else
               { errbuf(0,english(975));
                 /* In all other cases 300 is the maximum exponent. */
                 return 1;
               }
          }
     }
  u = ARG(0,t);
  k = (unsigned short) INTDATA(ARG(1,t));
  if(k==0)
     return 1;
  if(ARITY(u) > 2)  /* (a+b+c)�  */
     { a = u;
       if(get_mathmode() == AUTOMODE && INTDATA(ARG(1,t)) > 3)
           return 1;  /* expanding (a+b+c)^n leads to out-of-memory errors
                         all too easily. */
       SETFUNCTOR(a,'+',(unsigned short)(ARITY(u)-1));
       b = ARG(ARITY(u)-1,u);
       temp = make_term('+',2);
       ARGREP(temp,0,a);
       ARGREP(temp,1,b);
       return plainbinomialtheorem(make_power(temp,ARG(1,t)),arg,next,reason);
     }
  a = ARG(0,u);
  b = ARG(1,u);
  SET_ALREADY(a);  /* so polyval won't go into them */
  SET_ALREADY(b);
  if(k < 5)
      return binomialtheorem(t,arg,next,reason);
  strcpy(reason, english(427));  /* binomial theorem */
  /* for larger k we do not want to evaluate each binomial coefficient separately */
  c = bigint(1L);
  *next = make_term('+',(unsigned short)(k+1));
  ARGREP(*next,0, ONE(a) ? one : make_power(a,make_int(k)));
  ARGREP(*next,k, ONE(b) ? one : make_power(b,make_int(k)));
  for(i=1;i<=(k+2)/2;i++)
     { z1 = bigint(k-i+1);
       z2 = bigint(i);
       bigmult(c, z1,&w);
       bigdivide(w,z2,&q,&r);
       if(r.ln!=1 || r.val[0] != 0)
          assert(0);
       freespace(w.val);
       freespace(r.val);
       freespace(z1.val);
       freespace(z2.val);
       c=q;
       err = bignum_long(c,&clong);
       if(!err)
           d= make_int(clong);
       else
           d = make_bignum(c);
       if(ONE(a))
          ARGREP(*next,i,product(d,make_power(b,make_int(i))));
       else if(ONE(b))
          ARGREP(*next,i,product(d,make_power(a,make_int(k-i))));
       else
          ARGREP(*next,i,product3(d,make_power(a,make_int(k-i)),make_power(b,make_int(i))));
       if(2*i == k+2)
          break;  /* this was the middle term (k is even, there are an odd number of terms) */
       if(ONE(b))
          ARGREP(*next,k-i,product(d,make_power(a,make_int(i))));
       else if(ONE(a))
          ARGREP(*next,k-i,product(d,make_power(b,make_int(k-i))));
       else
          ARGREP(*next,k-i,product3(d,make_power(a,make_int(i)),make_power(b,make_int(k-i))));
     }
  HIGHLIGHT(*next);
  return 0;
}

/*________________________________________________________________________*/
MEXPORT_ALGEBRA int sigmatosum(term t, term arg, term *next, char *reason)
/* expand indexed sum to actual sum */
/* Difference of the limits must be an integer */
{ term u,l,dif,summand,index,w,temp;
  unsigned short   n;
  int i;
  if(FUNCTOR(t) != SUM)
     return 1;
  u = ARG(3,t);
  l = ARG(2,t);
  polyval(sum(u,tnegate(l)),&dif);
  if(NEGATIVE(dif))
      { if(!INTEGERP(ARG(0,dif)))
           { errbuf(0, english(817));
             /* Difference of upper and lower limit must be an integer */
             return 1;
           }
        *next = zero;
        return 0;
      }
  if(!ISINTEGER(dif))
      { errbuf(0,english(817));
        /* Difference of upper and lower limit must be an integer */
        return 1;
      }
  if(INTDATA(dif) > 100)
      { errbuf(0, english(819));  /* Too many terms */
        return 1;
      }
  strcpy(reason, english(820));   /* definition of � */
  n = (unsigned short  ) (INTDATA(dif) + 1);  /* number of terms in the sum */
  if(n==1)
     { psubst(l,ARG(1,t),ARG(0,t),next);
       HIGHLIGHT(*next);
       return 0;
     }
  summand = ARG(0,t);
  index = ARG(1,t);
  *next = make_term('+',n);
  for(i=0;i<n;i++)
     { polyval(sum(make_int(i),l),&w);
       subst(w,index,summand,&temp);
       value(temp,&u);
       ARGREP(*next,i,remove_zero_powers(u));
     }
  HIGHLIGHT(*next);
  return 0;
}
/*________________________________________________________________________*/
static term remove_zero_powers(term t)
/* apply the laws a^0 = 1  and a^1 = a throughout t, and then the law 1*a = a */
/* when expanding sigma notation we don't want zero exponents, which
   are undefined when the base is zero. Thus sum(x^i,i,0,2) = 1+x+x^2
   IS INDEED defined when x = 0 */
/* also returns e.g.  -2x^3  on (-2)x^3  */

{ unsigned short n=ARITY(t);
  unsigned short f = FUNCTOR(t);
  unsigned short k;
  int i;
  term u,ans;
  if(ATOMIC(t))
     return t;
  if(f== '^' && ZERO(ARG(1,t)))
     return one;
  if(f=='^' && ONE(ARG(1,t)))
     return ARG(0,t);
  ans = make_term(f,n);
  if(f == '*')
     { k = 0;
       for(i=0;i<n;i++)
          { u = remove_zero_powers(ARG(i,t));
            if(ZERO(u))
               return zero;
            if(!ONE(u))
               { ARGREP(ans,k,u);
                 k++;
               }
          }
       if(k==0)
          { RELEASE(ans);
            return one;
          }
       if(k==1)
          { u = ARG(0,ans);
            RELEASE(ans);
            return u;
          }
       SETFUNCTOR(ans,'*',k);
       if(NEGATIVE(ARG(0,ans)))
          { ARGREP(ans,0,ARG(0,ARG(0,ans)));
            return tnegate(ans);  /*  return -2x^3 instead of (-2)x^3  */
          }
       return ans;
     }
  for(i=0;i<n;i++)
     ARGREP(ans,i,remove_zero_powers(ARG(i,t)));
  return ans;
}

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