Sindbad~EG File Manager

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

/* Integration by parts */
/* M. Beeson, for MathXpert */
/*
Original date 1.15.91
modified 8.27.98
1.2.00 added error message 2392 to integratebyparts
10.6.00 modified equatetoproblem
8.28.04 modified equal_integrals
*/

#include <string.h>
#include <assert.h>
#define TRIGCALC_DLL
#include "globals.h"
#include "graphstr.h"
#include "document.h"
#include "ops.h"
#include "calc.h"
#include "checkarg.h"
#include "operator.h"
#include "probtype.h"
#include "cancel.h"
#include "polynoms.h"
#include "algaux.h"   /* subterm                     */
#include "nextstep.h" /* opseq                       */
#include "progress.h" /* display_integral_progress   */
#include "intsub.h"   /* simple_integral             */
#include "exec.h"     /* erasecolors                 */
#include "deriv.h"    /* derivative                  */
#include "order.h"    /* mvpoly                      */
#include "symbols.h"
#include "cflags.h"
#include "pvalaux.h"  /* ismonomial                  */
#include "errbuf.h"
#include "docdata.h"
#include "conparts.h" /* confirm_parts               */
#include "trig.h"     /* ARCTRIGFUNCTOR              */
#include "automode.h" /* get_activeline              */

static int tryparts(term udv, term x, term u, term *v, term *dv);
static int rejectparts(term u, term x);
static int equal_integrals(term u, term v);
static void protect_integrals(term t);
/*_______________________________________________________________________*/
static int rejectparts(term u, term x)
/* return 0 if du/dx is a rational function or a function of x^2,
or has x or a power of x in the denominator already
[so we have a reasonable chance of doing integral(xdu/dx,x)].
Return 1 otherwise. */

{ term du,xsq,v,a,b;
  unsigned short f = FUNCTOR(u);
  if(ARITY(u) == 1 && equals(ARG(0,u),x) &&
     (f == LN || f == LOG || f == ASIN || f == ATAN || f == ACOS || f == ACOT)
    )
     return 0;  /* ln and arcsin, etc. are integrated by parts */
  if((f == ASEC || f == ACSC) && FUNCTOR(ARG(0,u)) == ABS && equals(ARG(0,ARG(0,u)),x))
     return 0;  /* arcsec |x| and arccsc |x| can be integrated by parts although
                   arcsec x and arccsc only can be if we assume x > 0 or
                   assume x < 0. */
  du = derivative(u,x);
  if(NEGATIVE(du))
     du = ARG(0,du);
  if(FRACTION(du) && mvpoly(ARG(0,du)) && mvpoly(ARG(1,du)))
     return 0;  /* du/dx is a rational function */
  if(FRACTION(du) && equals(ARG(1,du),x))
     return 0;  /* x in the denominator */
  if(FRACTION(du) && ismonomial(ARG(1,du),x,&a,&b))
     return 0;  /* power of x in the denominator */
  xsq = make_power(x,two);
  subst(var0,xsq,du,&v);
  if(!contains(v,FUNCTOR(x)))
     return 0;   /* du/dx is a function of x^2  */
  /* Don't bother freeing memory as this will not be tried more than
     once; reset_heap will take care of it */
  return 1;
}

/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int autointegratebyparts(term t, term arg, term *next, char *reason)
/* computer chooses the parts and carries out integration by parts */
{ SETFUNCTOR(arg,ILLEGAL,0);
  return integratebyparts(t,arg,next,reason);
}

/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int integratebyparts(term t, term u, term *next, char *reason)
/* u is supplied by the user in menu mode */

/* in auto mode, if the integrand udv isn't a product or fraction we try only
u = udv, changing the integral to  integral(x du/dx,x).  Moreover,
this will be tried only if du/dx is either a function of x^2
(so it will simplify by substitution)  or a rational function,
as in case u = ln x or u = arctan x)

If the integrand is a product,  the rules are more complicated,
and are explained below.  If it's a fraction, we look for a log term in
the numerator, or a sin(ln x) or cos(ln x) numerator.
*/

{ term x,v,dv,uv,udv,vdu,cancelled,temp,w,num,denom;
  int m,err;
  int logflag=0;
  int transcendentalflag = 0;
  int arctrigflag = 0;
  unsigned short i,j,n,g;
  if(FUNCTOR(t) != INTEGRAL)
     return 1;
  if(IMPROPER(t))
     { errbuf(0, english(2392));
       /* Integration by parts cannot be applied to improper integrals directly.
          First express the integral as a limit. */
       return 1;
     }
  udv = ARG(0,t);
  x = ARG(1,t);
  if(FUNCTOR(u)!=ILLEGAL)  /* we're in menu mode or term selection mode */
     { if(FUNCTOR(u) == '=' && ISATOM(ARG(0,u)))
          u = ARG(1,u);   /* user entered literally ' u = ...';
                               just accept the right hand side. */
       if(!contains(u,FUNCTOR(x)))
          { errbuf(0,english(2480));
            /* The selected expression must contain the variable of integration. */
            return 1;
          }
       err= tryparts(udv,x,u,&v,&dv);
       if(err == 1)
          { errbuf(0, english(786));
               /* You must enter a term that divides the integrand */
            return 1;
          }
       if(err == 2)  /* can't integrate dv */
         { errbuf(0, english(787));
              /* MathXpert can't integrate 'dv' for this choice of 'u'  */
           errbuf(1, english(788));
              /* so that choice of u won't work. */
           return 1;
         }
     }
     /* in auto mode, we must find u ourselves */
 else if (FUNCTOR(udv) == '*')
    { n = ARITY(udv);

        /* We must divide the product into a part u to differentiate and
           a part dv to integrate.  Here are the rules:
             (1)  if any factor is a logarithm or a power of a logarithm,
             try that for the part to differentiate.

             (2) Otherwise if there is a polynomial and transcendental
             function among the factors, choose the transcendental function
             (or the product of the non-polynomial functions if there are
             other factors) as the part to integrate.  In other words,
             choose the polynomial as the part to differentiate.
             Exception:  if the transcendental part is an arctrig function,
             then differentiate IT, because it will become a rational or
             algebraic function.

             (3) If that fails, and the arg of the transcendental factors
             is (the same) polynomial, divide its derivative out of the
             polynomial and choose the quotient as the part to differentiate,
             as in  x^3 e^x^2, where u=x^2 works.

             (4) If that fails, look for an exponential term and if found,
                 integrate that.  (e.g. in  e^x sin x)

             (5) Otherwise give up--integrate by parts will likely
              lead to infinite regress.  (e.g. in sin x cos x)

        */

      for(i=0;i<n;i++)  /* see if there is a log or log-power term */
                        /* and at the same time count the non-log transcendentals */
         { u = ARG(i,udv);
           if(ATOMIC(u))
              continue;
           g = FUNCTOR(u);
           if(g==LN || (g=='^' && FUNCTOR(ARG(0,u))==LN))
              { cancel(udv,u,&cancelled,&dv);
                err = simple_integral(dv,x,&v);
                if(!err)
                   goto finish;
                ++logflag;   /* count the failures */
              }
           if(g == '^' && contains(ARG(1,u),FUNCTOR(x)))
              { ++transcendentalflag;
                continue;
              }
           if(g == '^')
              g = FUNCTOR(ARG(0,u));  /* e.g. u = sec^2 �  */
           if(ACOS <= g && g <= ATAN)
              ++arctrigflag;
           else if(g != LN && g != LOG && g != SQRT && g != ROOT && g != '/' &&
                   g != '*' && g != '+' && g != '-' && g != '^' && g != ABS
                  )
              ++ transcendentalflag;
         }
      if(logflag)
         return 1;  /* no use trying further */
      if(!transcendentalflag && !arctrigflag)
         return 1;
      for(i=0;i<n;i++)  /* Now there's no log term;  assuming the integrand
            has already been simplified, only one factor is a polynomial. */

         { u = ARG(i,udv);
           if(!contains(u,FUNCTOR(x)))
              continue;
           if(!ispolyin(u,x) && !arctrigflag)
              continue;  /* choose the polynomial part if there's no arctrig part */
           if(arctrigflag && (FUNCTOR(u) < ACOS || ATAN < FUNCTOR(u)))
              continue;  /* choose the arctrig part to differentiate */
           err = cancel(udv,u,&cancelled,&dv);
           if(err || !equals(cancelled,u))
              continue;
           err = simple_integral(dv,x,&v);
           if(!err)
              goto finish;
           /* for example x^4 e^x^3 comes to here */
           /* The following is rule (3) of the comments above */
           for(j=0;j<n;j++)
              { if(j!=i && !ATOMIC(ARG(j,udv)))
                    break;
              }
           assert(j<n);
           m = ARITY(ARG(j,udv));  /* for Bessel functions it can be > 1 */
           w = ARG(m-1,ARG(j,udv));
           if(ispolyin(w,x))
              { err = cancel(u,w,&cancelled,&temp);
                if(err)
                   break;   /* from the for-loop, go down to rule (4) */
                u = temp;
                err = cancel(udv,u,&cancelled,&dv);
                if(err)
                   break;   /* from the for-loop, go down to rule (4) */
                err = simple_integral(dv,x,&v);
                if(!err)
                   goto finish;
              }
         }
      for(i=0;i<n;i++)  /* Now look for an exponential (rule (4) above) */
         { dv = ARG(i,udv);
           if(!contains(dv,FUNCTOR(x)))
              continue;
           if(FUNCTOR(dv) != '^' || !equals(ARG(0,dv),eulere))
              continue;
           err = cancel(udv,dv,&cancelled,&u);
           if(err || !equals(cancelled,dv))
              continue;
           err = simple_integral(dv,x,&v);
           if(!err)
              goto finish;
         }
      return 1;  /* give up */
    }
 else if(FUNCTOR(udv) == '^')
    { if(contains(ARG(1,udv),FUNCTOR(x)))
         return 1;    /* it's hopeless to integrate a power with
                         nonconstant exponent by parts */
                      /* I only know one case where it works, namely
                         e^�x, but substitution treats this better. */
      if(SIGNEDFRACTION(ARG(1,udv)))
         return 1;    /* you'll never get anywhere differentiating
                         something to a fractional power. */
      if(obviously_negative(ARG(1,udv)))
         return 1;     /* likewise for negative powers */
      /* we would get the integral of xu^(n-1) u', so there's hope
      only if u' is u^(n-1) or an integer power of u times u^(n-1),
      In this case u' is a fractional power of u.  For example,
      u' = sqrt(u).  These differential equations don't have elementary
      solutions, I conjecture; at least I don't recognize them. Then
      let's not waste time trying to integrate by parts this way.
      */
      if(equals(ARG(1,udv),two))
         u = ARG(0,udv);
      else
         { term temp;
           value(sum(ARG(1,udv),minusone),&temp);
           u = make_power(ARG(0,udv),temp);
         }
      err = tryparts(udv,x,u,&v,&dv);
      if(err)
          return 1;
       else
          goto finish;
    }
 else if(FUNCTOR(udv) == '/')  /* example,  udv = (ln x)/x  */
    /* look for a LN term in the numerator */
    { num = ARG(0,udv);
      denom = ARG(1,udv);
      g = FUNCTOR(num);
      if(g == '^')
         { if(contains(ARG(1,num),FUNCTOR(x)))
              return 1;  /* nonconstant exponent in numerator */
           u = num;
           g = FUNCTOR(ARG(0,num));
           if(g != LN && g != LOG)
              return 1;
         }
      else if(g == LN || g == LOG)
         u = num;
      else if(g == '*' && ARITY(num) == 2)
         { /* example, x ln x / sqrt(x^2-1)  */
           for(i=0;i<2;i++)
              { u = ARG(i,num);
                if(FUNCTOR(u) == LN)
                   break;
              }
           if(i==2)
              return 1;  /* no LN factor found */
         }
      else if(equals(num,x))
         { u = num;  /* example, x/cos^2 x  */
           dv = reciprocal(denom);
         }
      else if(
              (g == SIN || g == COS) &&
              (FUNCTOR(ARG(0,num)) == LN || FUNCTOR(ARG(0,num)) == LOG) &&
              equals(ARG(0,ARG(0,num)),x) &&
              FUNCTOR(denom) == '^' &&
              equals(ARG(0,denom),x) &&
              ISINTEGER(ARG(1,denom))
             )
         { u = num;
           dv = reciprocal(denom);
         }
      else
         return 1;
      err = tryparts(udv,x,u,&v,&dv);
      if(err)
         return 1;
      else
         goto finish;
    }
 else /*  if(FUNCTOR(udv) != '*'  or '^' */
    { u = udv;
      /* check whether du is a rational function or a function of x^2,
         or has an x in the denominator already */
      if(rejectparts(u,x))
         return 1;
      err = tryparts(udv,x,u,&v,&dv);
      if(err)
         return 1;
      else
         goto finish;
    }

/* Now we have u and v that work */
 finish:
 if(equals(udv,u))
    { if(ARITY(t)==2)
          *next = sum(product(x,u), tnegate(integral(product(x,diff(u,x)),x)));
      else  /* a definite integral */
          *next = sum(
                      evalat(product(x,u),x,ARG(2,t),ARG(3,t)),
                      tnegate(definite_integral(product(x,diff(u,x)),x,ARG(2,t),ARG(3,t)))
                     );
      HIGHLIGHT(*next);
      strcpy(reason,"$�u dv = uv - �v du$");
      return 0;
    }
 if(get_mathmode() == MENUMODE)
    { term uatom,vatom;
      erasecolors(&v);   /* it was colored by integrate, and if we don't
                                erasecolors, it will come out colored  */

      uatom = MAKE_ATOM('u');
      vatom = MAKE_ATOM('v');  /* with no entry in varlist, etc. */
      err = confirm_parts(
                          and(
                               equation(uatom,u),
                               equation(vatom,equation(integral(dv,x),v))
                             )
                         );
      if(err)
         return 3;      /* user pressed Cancel, so don't
                           generate an error message. */
    }
 uv = product(u,v);
 if(equals(u,x))
    vdu = v;
 else
    vdu = product(v,diff(u,x));
 if(ARITY(t)==2)
    *next = sum(uv,tnegate(integral(vdu,x)));
 else
    *next = sum(
                evalat(uv,x,ARG(2,t),ARG(3,t)),
                tnegate(definite_integral(vdu,x,ARG(2,t),ARG(3,t)))
               );
 HIGHLIGHT(*next);
 strcpy(reason,"$�u dv = uv - � v du$");
 return 0;
}
/*__________________________________________________________*/
static int tryparts(term udv, term x, term u, term *v, term *dv)
/*  udv should be integrated by parts with respect to x, given u.
This function computes dv and integral(dv,x) to get *v.  Zero return
is success.  Other error values mean the following:
  1:  u does not divide udv (using cancel)
  2:  can't integrate dv
*/
{ term cancelled,temp;
  int err;
  if(equals(udv,u))  /* this is the special case when dv = dx; */
     { *v = x;
       *dv = one;
       return 0;
     }
  switch(FUNCTOR(udv))
     { case '^':  /* fall-through */
       case '*':
          err = cancel(udv,u,&cancelled,dv);
          if(err || !equals(cancelled,u))
             return 1;
          break;

       case '/':
          err = cancel(ARG(0,udv),u,&cancelled,&temp);
          if(err)
             return 1;
          *dv = make_fraction(temp,ARG(1,udv));
           break;
       default:  return 1;
     }
  err = simple_integral(*dv,x,v);
  if(err)
     return 2;
  return 0;
}

/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int equatetoproblem(term t, term arg, term *next, char *reason)
/* This equates the original problem to the current line.
 For example as in integrating e^x sin x by parts twice, then solving. */
 /* It is associated to INTEGRAL, but it works on the whole line,
 so it is listed as a JUMPER operator in ops.h */

{ term new,old,temp;
  int i,count;
  int currentline,problemtype;
  controldata cd;
  operation *opseq;
  problemtype = get_problemtype();
  if(problemtype == INDUCTION || get_selected_equation() != 0)
     return 1;  /* current line not necessarily equal to history[0] */
  currentline = get_activeline();
  i=currentline;
  get_controldata(&cd);
  opseq = cd.opseq;
  count = 0;
  new =  history(currentline);
  if(FUNCTOR(new) == '=')
     return 1;  /* prevent applying this operator in infinite regress */
  while(i>0)
     { if( opseq[i].men == integrate_by_parts
          && opseq[i].choice == 1
         )
          ++count;
       if(count>=2 && i>0 && equal_integrals(history(i-1),new))
          { old = history(i-1);
            goto done;
          }
       --i;
     }
  if(i==0 && get_mathmode() == AUTOMODE)
     return 1;  /* there haven't been two integrations by parts */
  if(i>0)
    old = history(i-1);  /* just before the first integration by parts */
  else
    old = history(0);  /* in menu mode when there weren't
                          two integrations by parts */
  /* It's not enough just to check if old is a subterm of new,
     because old could contain some other terms added to the integral.
     What we need to check is that there's just one integral in new,
     and that same integral is the only integral in old.
  */
  if(!equal_integrals(old,new))
     return 1;
  done:
  /* Now check to make sure that the integral occurs with a different sign or 
  coefficient in old and new */
  polyval(sum(old,tnegate(new)),&temp);
  if(!contains(temp,INTEGRAL))
      return 1;
  *next = equation(old,new);
  HIGHLIGHT(*next);
  strcpy(reason, english(789));   /* summary of work */
  protect_integrals(*next);
  /* prevent auto mode from starting all over again */
  PROTECT(ARG(1,*next));
  commentbuf(0,english(1993));
  /* This is an equation involving the desired integral. */
  return 0;
}
/*____________________________________________________________*/
MEXPORT_TRIGCALC int transferintegral(term eqn, term arg, term *next, char *reason)
/* when left side of equation eqn is an integral, transfer a copy
of it on the right to the left side. */
{ term t,rhs;
  unsigned short i,n;
  if(FUNCTOR(eqn) != '=')
     return 1;
  t = ARG(0,eqn);
  if(FUNCTOR(t) != INTEGRAL)
     return 1;
  rhs = ARG(1,eqn);
  if(FUNCTOR(rhs) != '+')
     return 1;
  n = ARITY(rhs);
  for(i=0;i<n;i++)
    { arg = ARG(i,rhs);
      if(subterm(t,arg))
          return transfer2(eqn,arg,next,reason);
    }
  return 1;
}
/*___________________________________________________________*/
static int extract_integral(term u, term *ans)
/* return 0 if u contains exactly one integral, and
if so put the integral in *ans; otherwise return 1.
*/
{ unsigned short n,f;
  int i,count;
  int flag;
  start:  /* label for tail recursion */
  f = FUNCTOR(u);
  if(f == INTEGRAL)
     { *ans = u;
       return 0;
     }
  if(ATOMIC(u))
     return 1;
  n = ARITY(u);
  if(n == 1)
     { u = ARG(0,u);
       goto start;
     }
  count = 0;
  for(i=0;i<n;i++)
     { if(contains(ARG(i,u),INTEGRAL))
          { ++count;
            flag = i;
          }
     }
  if(count != 1)
     return 1;
  u = ARG(flag,u);
  goto start;
}
/*______________________________________________________________*/
static int equal_integrals(term u, term v)
/* return 1 if u and v each contain exactly one integral,
and it's the same one, and there's no obvious reason why
we can't solve for that integral by setting u = v.
(For example, if u = v = the integral, that's a reason, or u = -(-v))
*/
{ term uIntegral,vIntegral;
  int err;
  /* these next lines prevent misapplications of equatetoproblem that 
     result e.g. in 0=0. */  
  if(FUNCTOR(u) == '-' && FUNCTOR(ARG(0,u)) == '-')
     u = ARG(0,ARG(0,u));
  if(FUNCTOR(v) == '-' && FUNCTOR(ARG(0,v)) == '-')
     v = ARG(0,ARG(0,v));
  if(FUNCTOR(u) == '-' && FUNCTOR(v) == '-')
     { u = ARG(0,u);
       v = ARG(0,v);
     }
  err = extract_integral(u,&uIntegral);
  if(err)
     return 0;
  err = extract_integral(v,&vIntegral);
  if(err)
     return 0;
  if(!equals(uIntegral,vIntegral))
     return 0;
  if(equals(u,uIntegral) && equals(v,uIntegral))
     return 0;
  return 1;
}

/*________________________________________________________________________*/
static void protect_integrals(term t)
/* PROTECT all integrals in t */
{ unsigned short n;
  int i;
  if(ATOMIC(t))
     return;
  if(FUNCTOR(t) == INTEGRAL)
     { PROTECT(t);
       return;
     }
  n = ARITY(t);
  for(i=0;i<n;i++)
     protect_integrals(ARG(i,t));
}

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