Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/algebra/
Upload File :
Current File : /usr/home/beeson/MathXpert/algebra/factcanc.c

/* M. Beeson, for MathXpert */
/* modified 3.13.98 */
/* 1.10.00  modified get_reason for differenceofnthpowers, etc. */
/* 9.26.14  added 3 lines of code around line 212   */


#include <assert.h>
#include <string.h>
#include <math.h>
#include "globals.h"
#include "ops.h"
#include "probtype.h"
#include "polynoms.h"
#include "order.h"
#include "cancel.h"
#include "algaux.h"
#include "simpsums.h"
#include "eqn.h"
#include "autosimp.h"  /* SetShowStepOperation */
#include "pvalaux.h"   /* mvpoly2              */

static int get_reason(term,term, char*);
static term  aux2(unsigned short n,int i,term num,term num2);
/*______________________________________________________________*/
int cancelgcd(term t, term arg, term *next, char *reason)
/* given a fraction t, whose num and denom are polynomials or
products containing polynomial factors, find the gcd of two of
the polynomial factors and show the factorization, so the term can
be cancelled next.  After the factorization is found using gcd's,
the operation tries to find a more elementary factorization formula
that would have yielded the same result and present THAT in the
reason string.  If not, it just says "common factor".
*/
{ term num,denom,num2,num1,denom1,denom2,temp,temp2,u;
  int i,j,err,err2;
  unsigned short path[12];
  unsigned short path2[12];
  unsigned short m,n;
  if (FUNCTOR(t) != '/' || PRIME(t))
   /* PRIME(t) for a fraction means it's in lowest terms.  In practice
      it means cancelgcd has been tried and failed already */
     return 1;
  num = ARG(0,t);
  denom = ARG(1,t);
  if(!mvpoly2(num) || !mvpoly2(denom))
     return 1;  /* num and denom must be polys (in some entire functions maybe)
                   Don't work on fractions containing roots or fractional exponents.
                   Example, if it worked on (3x sqrt y + 9 y)/(x^2-9y),
                   the result would be a mess involving lots of sqrt y terms
                */
  if(FUNCTOR(num) == '^' && INTEGERP(ARG(1,num)) && FUNCTOR(ARG(0,num)) == '+')
     { temp = make_fraction(ARG(0,num),denom);
       err = cancelgcd(temp,arg,&temp2,reason);
       if(err)
          return 1;
       *next = make_fraction(make_power(ARG(0,temp2),ARG(1,num)),ARG(1,temp2));
       HIGHLIGHT(*next);
       pathncopy(path2,12,get_pathtail());
       if(path2[0] == '/' && path2[1] == 1)
          { path[0] = '/';
            path[1] = 1;
            path[2] = '^';
            path[3] = 1;
            if(path2[2] == 0)
               path[4] = 0;
            else
               { for(j=4; j < 11 && path2[j-2]; j++)
                    path[j] = path2[j-2];
                 path[j] = 0;
               }
            set_pathtail(path);
          }
       return 0;
     }
  if(FUNCTOR(denom) == '^' && INTEGERP(ARG(1,denom)) && FUNCTOR(ARG(0,denom)) == '+')
     { temp = make_fraction(num,ARG(0,denom));
       err = cancelgcd(temp,arg,&temp2,reason);
       if(err)
          return 1;
       *next = make_fraction(ARG(0,temp2),make_power(ARG(1,temp2),ARG(1,denom)));
       HIGHLIGHT(*next);
       pathncopy(path2,12,get_pathtail());
       if(path2[0] == '/' && path2[1] == 2)
          { path[0] = '/';
            path[1] = 2;
            path[2] = '^';
            path[3] = 1;
            if(path2[2] == 0)
               path[4] = 0;
            else
               { for(j=4; j < 11 && path2[j-2]; j++)
                    path[j] = path2[j-2];
                 path[j] = 0;
               }
            set_pathtail(path);
          }
       return 0;
     }
  if(FUNCTOR(num) == '+' && FUNCTOR(denom)=='+' &&
     (contains(num,'^') || contains(denom,'^'))
       /* don't waste time on a quotient of linear polynomials */
    )
     { err = cancelgcd_aux(num,denom,&num2,&denom2);
       if(err)
          return 1;
       *next = make_fraction(num2,denom2);
       if(equals(*next,t))  /* num and denom differ by a minus sign,
                               as in (-a-b)/(a+b)  */
          { *next = minusone;
            HIGHLIGHT(*next);
            strcpy(reason,"(-a-b)/(a+b) = -1");
            return 0;
          }
       if(!equals(num,num2))
          HIGHLIGHT(ARG(0,*next));
       if(!equals(denom,denom2))
          HIGHLIGHT(ARG(1,*next));
       if(COLOR(ARG(0,*next)) && COLOR(ARG(1,*next)))
          HIGHLIGHT(*next);
       if(eqtest(num2,num))
          { path[0] = '/';
            path[1] = 2;
            path[2] = 0;
            err = get_reason(denom,denom2,reason);
          }
       else if(eqtest(denom2,denom))
          { path[0] = '/';
            path[1] = 1;
            path[2] = 0;
            err = get_reason(num,num2,reason);
          }
       else
          err = 1;
       if(err)
          strcpy(reason, english(433)); /* common factor */
       else
          set_pathtail(path);
       return 0;
     }
  if(FUNCTOR(num) == '+' && FUNCTOR(denom) == '*')
     { err = cancelgcd(make_fraction(denom,num),arg,&temp2,reason);
       if(err)
          return 1;
       *next = reciprocal(temp2);
       pathncopy(path2,12,get_pathtail());
       if(path2[0] == '/' && path2[1])
          { path2[1] = (unsigned short) (path2[1] == 2 ? 1 : 2);
            set_pathtail(path2);
          }
       if(COLOR(temp2))
          HIGHLIGHT(*next);
       return 0;
     }
  if(FUNCTOR(denom) == '+' && FUNCTOR(num) == '*')
     { n = ARITY(denom);
       for(i=0;i<n;i++)
          { u = ARG(i,denom);
            if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == '+')
               return 1; /* use pushminusin first */
                         /* 'expand' leaves terms like this now. */
          }
       n = ARITY(num);
       for(i=0;i<n;i++)
          { u = ARG(i,num);
            if(eqtest(u,denom))
                continue;   /* don't work on  2(-a-b)/(a+b) */
                            /* Remember, this function doesn't actually
                               cancel but only factors out so 'cancel'
                               can do the job. */
            err = cancelgcd_aux(u,denom,&num2,&denom2);
            if(!err)
               { if(eqtest(num2,u))
                    { err2 = get_reason(denom,denom2,reason);
                      HIGHLIGHT(denom2);
                      if(!err2)
                         { path[0] = '/';
                           path[1] = 2;
                           path[2] = 0;
                           set_pathtail(path);
                         }
                    }
                 else if(eqtest(denom2,denom))
                    { if(FUNCTOR(u) == '+')
                         { err2 = get_reason(u,num2,reason);
                           HIGHLIGHT(num2);
                           if(!err2)
                              { path[0] = '/';
                                path[1] = 1;  /* numerator */
                                path[2] = '*';
                                path[3] = (unsigned short)(i+1);
                                path[4] = 0;
                                set_pathtail(path);
                              }
                         }
                      else if(FUNCTOR(u) == '^' &&
                              FUNCTOR(ARG(0,u)) == '+' &&
                              FUNCTOR(num2) == '^' &&
                              equals(ARG(1,num2),ARG(1,u))
                             )
                         { err2 = get_reason(ARG(0,u),ARG(0,num2),reason);
                           if(!err2)
                              { path[0] = '/';
                                path[1] = 1;
                                path[2] = '*';
                                path[3] = (unsigned short)(i+1);
                                path[4] = '^';
                                path[5] = 1;
                                path[6] = 0;
                                set_pathtail(path);
                              }
                         }
                      else
                         { err2=1;    // make sure err2 has a value
                           HIGHLIGHT(num2);
                           HIGHLIGHT(denom2);
                         }
                    }
                 else
                    { err2 = 1;
                      HIGHLIGHT(num2);
                      HIGHLIGHT(denom2);
                    }
                 if(err2)
                    strcpy(reason, "common factor"); /* english(433)*/
                 break;
               }
          }
       if(i==n)
          return 1;
       num1 = aux2(n,i,num,num2);
       *next = make_fraction(num1, denom2);
       return 0;
     }
  if(FUNCTOR(num) == '*' && FUNCTOR(denom)=='*')
     { n = ARITY(num);
       m = ARITY(denom);
       for(i=0;i<n;i++)
          { num1 = ARG(i,num);
            if(ATOMIC(num1))
               continue;
            for(j=0;j<m;j++)
               { denom1 = ARG(j,denom);
                 if(ATOMIC(denom1))
                     continue;
                 err= cancelgcd_aux(num1,denom1,&num2,&denom2);
                 if(!err)
                    { if(eqtest(num2,num1))
                         { err2 = FUNCTOR(denom1) == '+' ? get_reason(denom1,denom2,reason) : 1;
                           if(!err2)
                              { path[0] = '/';
                                path[1] = 2;
                                path[2] = '*';
                                path[3] =(unsigned short)(j+1);
                                path[4] = 0;
                                set_pathtail(path);
                              }
                           HIGHLIGHT(denom2);
                         }
                      else if(eqtest(denom2,denom1) && FUNCTOR(num1) == '+')
                         { err2 = FUNCTOR(num1)== '+' ? get_reason(num1,num2,reason) : 1;
                           if(!err2)
                              { path[0] = '/';
                                path[1] = 1;
                                path[2] = '*';
                                path[3] =(unsigned short)(i+1);
                                path[4] = 0;
                                set_pathtail(path);
                             }
                           HIGHLIGHT(num2);
                         }
                      else
                         { err2 = 1;
                           HIGHLIGHT(num2);
                           HIGHLIGHT(denom2);
                         }
                      if(err2)
                         strcpy(reason,english(433)); /* common factor") */
                      break;
                    }
               }
            if(j<m)
               break;
          }
       if(i==n)
          return 1;
       if(equals(num2,ARG(i,num)))
           num1 = num;
       else
           num1= aux2(n,i,num,num2);
       if(equals(denom2,ARG(j,denom)))
           denom1 = denom;
       else
           denom1 = aux2(m,j,denom,denom2);
       copy(num1,&temp);   /* ensure no DAGS created */
       copy(denom1,&temp2);
       *next = make_fraction(temp, temp2);
       return 0;
     }
  return 1;
}

/*___________________________________________________________*/
static int get_reason(term t,term u, char *reason)
/* t is a sum, u is a factorization of t; get a good reason string
to show for this factorization, i.e. the menu name of a factorization
operator that will get that result.
   Calls SetShowStepOperation with that factorization operator
for argument.  But the calling function must make the corresponding
calls to set_pathtail.
*/
{ unsigned short n = ARITY(t);
  unsigned short m;
  term p,q,w,r;
  char buffer[DIMREASONBUFFER];
  int err;
  if(FUNCTOR(t) != '+')
     assert(0);
  if(NEGATIVE(u))
     u = ARG(0,u);
  if(n==2 && FUNCTOR(u) == '*')
     { if(ARITY(u) > 2)
          { /* example, 5a^2 + 20a = 5a(a+4)  */
            /* It must be contentfactor */
            strcpy(reason, "ab + ac = a(b+c)");
            SetShowStepOperation(contentfactor);
            return 0;
          }
       p = ARG(0,u);
       q = ARG(1,u);
       m = ARITY(p);
       if(ARITY(q) > 3  && m == 2)
          { err = differenceofnthpowers(t,zero,&w,reason);
            if(!err && equals(ARG(0,w),ARG(0,u)))
               { polyval1(sum(ARG(1,w),strongnegate(ARG(1,u))),&r);
                 if(ZERO(r))
                    { SetShowStepOperation(differenceofnthpowers);
                      return 0;
                    }
               }
            err = differenceofnth2(t,zero,&w,reason);
            if(!err && equals(ARG(0,w),ARG(0,u)))
               { polyval1(sum(ARG(1,w),strongnegate(ARG(1,u))),&r);
                 if(ZERO(r))
                    { SetShowStepOperation(differenceofnth2);
                      return 0;
                    }
               }
            err = sumofnthpowers(t,zero,&w,reason);
            if(!err && equals(ARG(0,w),ARG(0,u)))
               { polyval1(sum(ARG(1,w),strongnegate(ARG(1,u))),&r);
                 if(ZERO(r))
                    { SetShowStepOperation(sumofnthpowers);
                      return 0;
                    }
               }
          }
       if(ARITY(q) == m &&
             /* but the arity doesn't have to be 2 if a or b is a sum */
          FUNCTOR(p) == '+' && FUNCTOR(q) == '+' &&
          /* careful, 3x^2 - 27 = (x-3)(3x+9); in this example, we don't want to
             make ShowStep highlight differenceofsquares. */
          NEGATIVE(ARG(m-1,p)) &&
          (
            (equals( ARG(0,ARG(m-1,p)),ARG(m-1,q)) && equals(ARG(0,p),ARG(0,q))) ||
            (equals( ARG(m-1,q),ARG(0,p)) && m == 2 && equals(ARG(0,ARG(m-1,p)),ARG(0,q)))
          )
         )
          { strcpy(reason, "a^2-b^2=(a-b)(a+b)");
            SetShowStepOperation(differenceofsquares);
            return 0;
          }
       else if(!contains(ARG(0,u), '+'))
          { strcpy(reason, "ab + ac = a(b+c)");
            SetShowStepOperation(contentfactor);
            return 0;
          }
       else if(!contains(ARG(1,u), '+'))
          { strcpy(reason,"ac + bc = (a+b)c");
            SetShowStepOperation(contentfactor);
            return 0;
          }
       else if(ARITY(ARG(0,u)) == 2 && FUNCTOR(ARG(0,u)) == '+' &&
               ARITY(ARG(1,u)) == 3 && NEGATIVE(ARG(1,t))
              )
          { strcpy(reason,"a^3-b^3=(a-b)(a^2+ab+b^2)");
            SetShowStepOperation(differenceofcubes);
            return 0;
          }
       else if(ARITY(ARG(0,u)) == 2 && ARITY(ARG(1,u)) == 3)
          { strcpy(reason,"a^3+b^3=(a+b)(a^2-ab+b^2)");
            SetShowStepOperation(sumofcubes);
            return 0;
          }
       else
          return 1;  /* factoring a^n-b^n is too long a reason string */
                     /* it also could be factoring x^4+a^4          */
     }
  if(n > 3)
     return 1;
  if(FUNCTOR(u) == '^' && ARITY(u) == 2 && NEGATIVE(ARG(1,u)))
     { strcpy(reason,"a^2-2ab+b^2=(a-b)^2");
       SetShowStepOperation(factorsquareofdif);
       return 0;
     }
  if(FUNCTOR(u) == '^' && ARITY(u) == 2)
     { strcpy(reason,"a^2+2ab+b^2=(a+b)^2");
       SetShowStepOperation(factorsquareofsum);
       return 0;
     }
  if(FUNCTOR(u) == '*' && ARITY(u) == 2 &&
     FUNCTOR(ARG(0,u)) == '+' && ARITY(ARG(0,u)) == 2 &&
     FUNCTOR(ARG(1,u)) == '+' && ARITY(ARG(1,u)) == 2 &&
     !factorquadratic(t,zero,&w,buffer)
    )
     { strcpy(reason, english(325));  /* factor quadratic */
       SetShowStepOperation(factorquadratic);
       return 0;
     }
  return 1;
}
/*_____________________________________________________________*/
int factorandcancel(term t, term arg, term *next, char *reason)
/* factor one or both sides of an identity if the result will
permit a cancellation. Does not carry out the cancellation. */
{ int err;
  term u,v,w;
  unsigned short path[32];
  if(FUNCTOR(t) != '=')
     return 1;
  u = ARG(0,t);
  v = ARG(1,t);
  err = cancelgcd(make_fraction(u,v),arg,&w,reason);
  pathncopy(path,32,get_pathtail());
  if(path[0] == '/')
     { path[0] = '=';
       set_pathtail(path);
     }
  if(err || !FRACTION(w))
     return 1;
  *next = equation(ARG(0,w),ARG(1,w));
  return 0;
}
/*______________________________________________________________*/

static term aux2(unsigned short n,int i,term num,term num2)
/* Return a term equal to num with num2 replacing the i-th
argument of num, which is supposed to be a product of n terms.
Return the replaced term, flatten (if num2 was a product),
sort the args; if the two args of num2
are equal, make them a square; if num2 is a negation, pull the
sign to the front.  Return the resulting term.
   Must not alter the original term num.
*/

{ term u,ans;
  int j;
  unsigned short m;
  if(NEGATIVE(num2))
     return tnegate(aux2(n,i,num,ARG(0,num2)));
  if(FUNCTOR(num2) != '*')
      { ans = make_term('*',n);
        for(j=0;j<n;j++)
           ARGREP(ans,j, i==j ? num2 : ARG(j,num));
        return ans;
      }
  m = ARITY(num2);
  ans = make_term('*',(unsigned short)(n+m-1));
  for(j=0;j<i;j++)
     ARGREP(ans,j, ARG(j,num));
  for(j=i;j<n-1;j++)
     ARGREP(ans,j,ARG(j+1,num));
  if(m==2 && equals(ARG(0,num2),ARG(1,num2)))
     { ARGREP(ans,n-1,make_power(ARG(0,num2),two));
       SETFUNCTOR(ans,'*',n);
       HIGHLIGHT(ARG(n-1,ans));
      }
  else for(j=n-1;j<n+m-1;j++)
     { u = ARG(j-n+1,num2);
       HIGHLIGHT(u);
       ARGREP(ans,j,u);
     }
/*  if(FUNCTOR(num1) == '*')
     sortargs(num1);  */
  return ans;
}

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