Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/polyval/
Upload File :
Current File : /usr/home/beeson/MathXpert/polyval/simpsums.c

/* operators from simpsums menu */
/* except orderterms, which is in order.c */
/*
M. Beeson
11.21.90 original date
6.26.98 last modified
*/

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

#include "globals.h"
#include "ops.h"  /* prototypes of operators */
#include "prover.h"
#include "order.h"
#include "cancel.h"
#include "integral.h"
#include "factor.h"  /* ratpart2 */
#include "mpmem.h"
#include "deval.h"
#include "pvalaux.h"  /* summands */
#include "simpsums.h"

static int calc_combines(unsigned short, term, term, term *);
static int cancel_integral(term *buffer,int k, int i,int j,term *ans);
/*____________________________________________________________________*/
static void actuallycancel(term *buffer1, int n, int i, int j, term *buffer2)

/* having determined that buffer1[i] and buffer1[j]  have different
signs, produce buffer2 by making a copy of buffer1 omitting those two
terms. n is the dimension of buffer1.  */

{ int p,max,min;
  min = ( (i<j) ? i : j );
  max = ( (i<j) ? j : i );
  for(p = 0; p < min; p++)
     buffer2[p]= buffer1[p];
  for(p=min;p+1<max;p++)
     buffer2[p] = buffer1[p+1];
  for(p=max-1;p<n-2;p++)
    buffer2[p] = buffer1[p+2];
}

/*_____________________________________________________________________*/
static int combines(term a,term b, term *ans)
/* Combine like terms such as 2xy^2 and 3xy^2.
Combine axy^2 and bxy^2 to (a+b)xy^2 if a and b are constant,
but don't collect  a and b in  a + b + x^2 to get (a+b) + xy^2, as the
term will just be flattened again, creating an infinite loop.
Return 1 for success, putting the answer in *ans.
Return 0 for failure.
Return -1 for a cancellation .
*/

{ term na,ca,sa,nb,cb,sb;
  term temp,val,temp2,temp3,temp4;
  aflag arithflag = get_arithflag();
  int err;
  ncs(a,&na,&ca,&sa);
  ncs(b,&nb,&cb,&sb);
  if(!equals(sa,sb))
     { if(ATOMIC(a) || ATOMIC(b))
          return 0;
       if(
              ( contains(a,INTEGRAL) && contains(b,INTEGRAL) && calc_combines(INTEGRAL, a,b,ans))
           || ( contains(a,DIFF) && contains(b,DIFF) && calc_combines(DIFF, a,b,ans))
         )
          { HIGHLIGHT(*ans);
            return 1;
          }
       if(FUNCTOR(sa) == FUNCTOR(sb))
          { unsigned f = FUNCTOR(sa);
            if(f==ABSFUNCTOR && eqtest(ARG(0,sa),ARG(0,sb)))
               sb = sa;  /* and go on */
            else if(f == '^' && equals(ARG(1,sa),ARG(1,sb)) && INTEGERP(ARG(1,sa)))
               { int r = eqtest(ARG(0,sa),ARG(0,sb));
                 if(!r)
                    return 0;
                 sb = sa;
                 if(ISODD(ARG(1,sa)) && r == -1)
                    nb = tnegate(nb);
                 /* and go on */
               }
            else
               return 0;  /* failure */
          }
       else
          return 0;  /* failure */
     }
  if(equals(ca,cb)) /* a common case */
    /* then ans = (na + nb)(ca * sa)  */
    /* unless na + nb = 0, in which case this is a cancellation */
    { if(ZERO(na))
         { *ans = product3(nb,ca,sa);
           return 1;
         }
      if(ZERO(nb))
         { *ans = product3(na,ca,sa);
           return 1;
         }
      if(equals(ca,infinity))
         { /* don't cancel infinity - infinity = 0;
              also don't cancel 2 infinity - infinity = infinity
           */
           double z,w;
           deval(na,&z);
           if(z == BADVAL)
              return 0; /* failure to combine */
           deval(nb,&w);
           if(w == BADVAL)
              return 0;
           if(z >= 0.0 && w <= 0.0)
              return 0;
           if(z <= 0.0 && w >= 0.0)
              return 0;
         }
      temp = sum(na,nb);
          /* if arithflag.comdenom==0, we don't get the value zero below
             in order to cancel a term with a fractional numerical part;
             therefore check it directly */
      if(
          (NEGATIVE(na) && equals(ARG(0,na),nb)) ||
          (NEGATIVE(nb) && equals(ARG(0,nb),na))
        )
         { *ans = zero;
           return -1;  /* a cancellation */
         }
      if(equals(na,nb))
         { value(product(two,na),&nb);
           *ans = product3(nb,ca,sa);
           HIGHLIGHT(*ans);
           return 1;
         }
      if(get_polyvalfunctionflag())
         { /* let's be sure to cancel sqrt(2) and  2^(1/2) etc.  */
           double z;
           long kk;
           deval(temp,&z);
           if(z != BADVAL && nearint(z,&kk) && kk==0)
              { *ans= zero;
                return -1;  /* a cancellation */
              }
          }
      err = value(temp,&val);  /* val is a term representing a number */
      if(!err && ZERO(val))
         { *ans = zero;
           return -1;  /* a cancellation */
         }
      if(arithflag.comdenom==0 &&
         contains(temp,'/')
        )
            /* for example, 1/x and 1/2x don't combine under
               the stated conditions; automode will use
               common denominators; also 1/2x and 1/2x or even
               1/2 and 1/2 do not combine; automode will use
               addfractions.
                  When not in automode, "collect like terms" will
               set arithflag.comdenom to 1 first so that the user
               can collect such terms if desired; this code is
               to control automode when adding numerical fractions.
            */
         return 0;
      if(err && !(ONE(ca) && ONE(sa)))
         { *ans = product3(temp,ca,sa);
           /* example:  x + sqrt(5)x  combines to (1+sqrt 5) x */
           HIGHLIGHT(*ans);
           return 1;
         }
      if(err) /* && ONE(ca) && ONE(sa) */
         /* e.g.  temp = 1 + sqrt 5; they don't really combine.
            But,  consider temp = sqrt 5 + 2 sqrt 5; these DO combine to 3 sqrt 5.
         */
          { term c,nc,sc,d,qq;
            int i;
            assert(FUNCTOR(temp) == '+');
            naive_gcd(ARG(0,temp),ARG(1,temp),&c);
            if(FUNCTOR(c) == '*' && (INTEGERP(ARG(0,c)) || RATIONALP(ARG(0,c))))
                { ratpart2(c,&nc,&sc);
                  c = sc;   /* reject any rational part of the gcd  */
                }
                      /* example, (1/12) sqrt 5 + (1/3) sqrt 5;  naive_gcd
                         returns (1/3) sqrt 5 and we only want c = sqrt 5  */
            if(ONE(c) || equals(minusone,c) || RATIONALP(c))
               /* the last RATIONALP to prevent (1/2) u + (1/2) v = (u + v)(1/2)
                  where u and v are e.g. cube roots of complicated numerical
                  expressions */
               { RELEASE(temp);
                 return 0;   /* they don't combine */
               }
            else
               { int saveit = arithflag.comdenom;
                 term copyofc;
                 copy(c,&copyofc);
                 qq = make_term('+',2);
                 for(i=0;i<2;i++)
                    { polyval(make_fraction(ARG(i,temp),i ? copyofc : c),ARGPTR(qq)+i);
                      /* use copyofc so that qq will be a tree not a DAG */
                    }
                 if( contains(ARG(0,qq),'/') && contains(ARG(1,qq),'/'))
                     { arithflag.comdenom = 0;
                       set_arithflag(arithflag);
                     }
                  /* (1/2) sqrt 5 + (1/3) sqrt 5 = (1/2 + 1/3) sqrt 5, because
                     the following code will fail and contentfactor will
                     get called.  But this code will succeed on
                     sqrt 5 + (1/3) sqrt 5 = (4/3) sqrt 5  */
                 err = value(qq,&d);
                 arithflag.comdenom = saveit;
                 set_arithflag(arithflag);
                 if(err!=0 && err !=2)
                    { /* after all they don't combine */
                      RELEASE(temp);
                      RELEASE(qq);
                      if(!OBJECT(c))
                         destroy_term(copyofc);
                      return 0;
                    }
                 err = value(product(d,c),&val);
                 if(err)
                     val = product(d,c);
                 /* That's the numerical part.  Don't forget
                    the constant and symbolic parts. */
                 *ans = product3(val,ca,sa);
                 HIGHLIGHT(*ans);
                 return 1;  /* they do combine */
               }
          }
      if(ONE(ca) && ONE(sa))  /* then this is really arithmetic */
                 /* In automode, arithmetic will be called first, so you
               won't get here while collecting like terms. However, this
               is also called by polyval, which needs it to do arithmetic. */
          { *ans = val;
            return 1;    /* succeed */
          }
      if(ZERO(val))  /* then this is a cancellation, not a combination */
          {*ans = zero;
           return -1;
          }
      if(ONE(ca) && ONE(sa))
         *ans = val;
      else if(ONE(ca))
         mfracts(val,sa,ans);
      else if(ONE(sa))
         mfracts(val,ca,ans);
      else
        { mfracts(ca,sa,&temp2);  /* multiply ca and sa and flatten */
          mfracts(val,temp2,ans);
        }
      RELEASE(temp);   /* allocated above in this function */
      HIGHLIGHT(*ans);
      if(PROTECTED(a) || PROTECTED(b))
          PROTECT(*ans);
      return 1;  /* success */
    }
   /* symbolic parts equal, constant parts not equal */
   else if(ONE(sa))
      return 0;  /* don't combine stand-alone constants, see above */
   else if(!iscomplex(sa) && 
          ((iscomplex(ca) && !iscomplex(cb)) || (iscomplex(cb) && !iscomplex(ca)))
          )
     return 0;  /* don't combine  ax + bx  when x does not contains 'i' and exactly one of 'a' or 'b' does,
                   because then in ax + bx + y,  you'll get a loop to (a+b)x + y and back. */          
     
  /* form (na*ca + nb*cb) * sa */
  mfracts(na,ca,&temp2);
  mfracts(nb,cb,&temp3);
  at(temp2,temp3,&temp4);
  mfracts(temp4,sa,ans);
  HIGHLIGHT(*ans);
  return 1;
}
/*____________________________________________________________________*/
#define MAXNOMEM 6  /* max number of terms to collect without memory management */
#define MAXCOLLECT 60  /* max number of terms to collect at all */

int collect1(int initiali, term t, term *next, int *cancel)
/* collect one group of like terms, among the args of t numbered
   initiali or greater.  t must be a sum.
   ARG(*index,*next) will be the arg that is newly created.
   *cancel will be 1 if a cancellation of several terms occurred,
   2 if a cancellation of only two terms occurred,
   0 if only a combination.
   return 0 for success, 1 for failure to find anything to do,
   in which case *next and *cancel are garbage.
*/

{ unsigned short i,j,k;
  unsigned short n = ARITY(t);
  term a,b;
  void  *savenode;
  unsigned long nbytes;
  int *scratch;  /* scratch[j] = 1 if j-th arg combines with i-th one  */
  int count;   /* how many terms besides ARG(i,t) combine with ARG(i,t) */
  *cancel=-1;   /* Nothing has happened yet */
  if(FUNCTOR(t) != '+')
     return 1; /* inapplicable */
  scratch = (int *) callocate(n,sizeof(int));
  if(scratch==NULL)
     nospace();
  if(n > MAXCOLLECT)
     return 1;   /* too many terms, don't risk running out of memory */
  if(n > MAXNOMEM)
     { nbytes = mycoreleft();
       if(nbytes < 24576)  /* leave 24K protected */
          return 1;   /* don't run out of memory.  Better to leave terms
                         uncollected! */
       savenode = heapmax();
     }
  for(i=initiali;i<n; i++)  /* see what collects with ARG(i,t) */
    { a = ARG(i,t);
      count = 0;
      for(k=0; k<n; k++)
         scratch[k] = 0;
      for(j=i+1;j<n;j++)
         { if(combines(a,ARG(j,t),&b))
              { scratch[j] = 1;
                if(ZERO(b) && *cancel == -1)  /* this a isn't the result of a previous combination */
                   { *cancel = 2;  /* so this is a binary cancellation */
                     a=b;
                     ++count;
                     break;
                   }
                else if(ZERO(b))
                   { *cancel = 1;
                     a=b;
                     ++count;
                     break;
                   }
                else
                   *cancel = 0;  /* Now don't call it a binary cancellation
                                      if something later cancels with b */
                a=b;
                ++count;
              }
         }
      if(count)  /* found a combination */
         { HIGHLIGHT(a);
           if(n==count+1)  /* all the terms combined into one term */
              { *next = a;
                free2(scratch);
                if(ZERO(a))
                   *cancel = 1;
                goto success;
              }
           assert(n-count >= 2);
           if(!ZERO(a))
              { *next = make_term('+',(unsigned short)(n-count));
                ARGREP(*next,i,a);
              }
           else if(n-count-1 == 1)  /* only one term will be left */
              { if(i)  /* the first term is the one left over */
                   *next = ARG(0,t);
                else
                   { for(j=1;j<n;j++)
                        { if(scratch[j] == 0)
                                 /* the j-th term did not combine
                                    so it is the leftover term */
                             break;
                        }
                     *next = ARG(j,t);
                   }
                free2(scratch);
                HIGHLIGHT(*next);
                if(*cancel != 2)
                   *cancel = 1;
                goto success;
              }
           else  /* don't put zero in explicitly */
              *next = make_term('+',(unsigned short)(n-count-1));
           for(k=0;k<i;k++)
              ARGREP(*next,k,ARG(k,t));
           j = i+1;
           k = ZERO(a) ? i : i+1;
           while(k < ARITY(*next))
             { if(! scratch[j])
                  { ARGREP(*next,k,ARG(j,t));
                    ++k;
                  }
               ++j;
             }
           if(ZERO(a) && *cancel != 2)
              *cancel = 1;
           free2(scratch);
           goto success;
         }
    }
  if(n > MAXNOMEM)
     reset_heap(savenode);
  return 1;  /* if you get here there's no combination */
  success:
     if(n > MAXNOMEM)
        save_and_reset(*next,savenode,next);
     return 0;

}

/*_____________________________________________________________________*/
void collect_aux2(term t, term *next, int *cancelflag, int *collectflag)
/* perform all possible collections and cancellations on t,
  returning in cancelflag and collectflag how many of each were done;
  like collect_aux, but it doesn't bother with reason.
  Works on sums, or on both sides of an equation or inequality, or on
all args of an AND */
{ int err,cancel_occurred;
  term temp,new;
  unsigned short f = FUNCTOR(t);
  unsigned short n = ARITY(t);
  unsigned short i,j;
  int pp,qq;
  temp = t;
  err=0;
  *cancelflag=*collectflag=0;
  if(f == AND || f == '=' || f == '<' || f == '>' || f == LE || f == GE)
     { *next = make_term(f,n);
       for(i=0;i<n;i++)
          { collect_aux2(ARG(i,t),ARGPTR(*next)+i,&pp,&qq);
            *cancelflag +=pp;
            *collectflag +=qq;
          }
       if(collectflag ==0 && cancelflag==0)
          { RELEASE(*next);
            *next = t;
          }
       return;
     }
  if(f != '+')
     { *next  = t;
       return;
     }
  j = 0;
  while(err==0 && j < ARITY(temp)-1)
     { err = collect1(j,temp,&new,&cancel_occurred);
       if(err == 0)
          { temp = new;
            *cancelflag += cancel_occurred;
            ++*collectflag;
            if(!cancel_occurred)
               ++j;
          }
     }
  if( !*cancelflag && !*collectflag) /* nothing done */
     *next = t;
  else
     { *next = temp;
       if(FUNCTOR(*next) == '+')
          additive_sortargs(*next);  /* put the args in order if something else is done */
     }
  return;
}

/*_____________________________________________________________________*/
#define ZZ(t)  (ZERO(t) || (OBJECT(t) && TYPE(t) == DOUBLE && nearint(DOUBLEDATA(t),&kk) && kk==0))
int dropzero(term t, term arg, term *next, char *reason)
/*  x + 0 = x;  drop all 0's or -0's from a sum */
/*  Also does x - 0 = x.   */
{ int i,j,m;
  int k= -1;  /* index of the first non-zero summand */
  long kk;
  int n = ARITY(t);
  if(FUNCTOR(t) != '+')
     return 1;  /* inapplicable */
      /* count how many terms must be dropped */
  for(i=j=0; i<n;i++)
     { if(ZZ(ARG(i,t)))
          ++j;
       else if(FUNCTOR(ARG(i,t)) == '-' && ZZ(ARG(0,ARG(i,t))))
          ++j;
       else if(k < 0)
          k=i; /* mark the first nonzero summand */
     }
  if(j==0)
     return 1;   /* no zeroes to be dropped */
  if(j==n)  /* every summand was  \pm  0 */
     { *next = zero;
       strcpy(reason, "0 \\pm 0 = 0");
       HIGHLIGHT(*next);
       return 0;
     }
  if(j==n-1)   /* all but one term was 0 */
     { *next =  ARG(k,t);
       if (k > 0)
          strcpy(reason,"0+x = x");
       else
          strcpy(reason,"x+0 = x");
       HIGHLIGHT(*next);
       return 0;
     }
    /* Now, with at least 2 nonzero summands, we must make a new sum */
  *next = make_term('+',(unsigned short)(n-j));
  for(i=m=0;i<n;i++)
      /* put the i-th old term, if nonzero, in position m in the new term */
    { if(! ZERO(ARG(i,t)) &&
         !  (FUNCTOR(ARG(i,t)) == '-' && ZZ(ARG(0,ARG(i,t))) )
        )
         { ARGREP(*next,m,ARG(i,t));
           ++m;
         }
    }
  if (k > 0)
     strcpy(reason,"0+x = x");
  else if(n == 2 && NEGATIVE(ARG(1,t)))
     strcpy(reason,"x-0 = x");
  else
     strcpy(reason,"x+0 = x");
  HIGHLIGHT(*next);
  return 0;
}

/*____________________________________________________________________*/
int collect(term t, term *next )
/* NOT an operator; performs all collections and cancellations in sum t */
/* Zero return means nothing collects or cancels */
/* return value 1 means no cancellation, only collection;
   return value 2 means cancellation, no collection;
   return value 3 means both occurred */
/* Will work simultaneously on both sides of an equation or inequality,
   and on all equations (or inequalities) in an AND */

{ int cancelflag,collectflag;
  int retval = 0;
  char localbuf[80];
  int err;
  unsigned short n;
  term temp;
  long nbytes;
  if(FUNCTOR(t) != '+')
     { *next = t;
       return 0;
     }
  n = ARITY(t);
  if(n > MAXNOMEM && !mvpoly2(t))
     { nbytes = mycoreleft();
       if(nbytes < 24576)
          { /* less than 24K available, don't risk running out of memory */
            *next = t;
            return 0;
          }
     }
  collect_aux2(t,&temp,&cancelflag,&collectflag);
  if(collectflag)
     retval |= 1;
  if(cancelflag)
     { retval |= 2;  /* and there can be zeroes in temp, which we now remove */
       err = dropzero(temp,zero,next,localbuf);
       if(err)
          *next = temp;
     }
  else
     *next = temp;
  return retval;
}
/*_______________________________________________________________*/
static int calc_combines(unsigned short f, term a, term b, term *ans)
/* combine terms with the same INTEGRAL or same DIFF as a factor.
f is either INTEGRAL or DIFF.  The terms are assumed not to have
the same symbolic part and both contain the functor f somewhere;
and they aren't atomic.
Return 1 if the terms combine (and the combined term in *ans);
return 0 for failure */

{ term c,newa,newb,trash;
  int err;
  naive_gcd(a,b,&c);
  if(!contains(c,f))
     return 0;
  err = cancel(a,c,&trash,&newa);
  if(err)
     return 0;
  err = cancel(b,c,&trash,&newb);
  if(err)
     return 0;
  *ans = product(c,sum(newa,newb));
  sortargs(*ans);
  return 1;
}
/*____________________________________________________________________*/
int additivecancel_aux(term *buffer1, unsigned short k, term *buffer2, unsigned short *m, term *cancelled)
/* because needed in simpsum.c */
/* perform an additive cancellation on the terms in buffer1 (of dimension k)
   and put the remaining terms in buffer2, setting *m to the number of
   terms placed in this buffer.  On failure, *m must be set to k, but
   buffer2 need not actually contain a copy of buffer1, it can be garbage.
   Buffer2 is assumed to have dimension at least k at input.
   Return 0 if cancellation is possible, 1 if not */

{ int i,j,q;
  term s;  /* for the term to be cancelled */
  int err;
  for(i=0;i<k;i++)
     { if(FUNCTOR(buffer1[i])== '-' )  /* a candidate for cancellation */
          { s = ARG(0,buffer1[i]);
            for (j=0;j<k; j++)
               { if(j != i && equals(buffer1[j],s))
                   /* s apparently cancels, but if it involves an
                      indefinite integral, we are allowed to
                      cancel it only by introducing a constant
                      of integration that depends on all the other
                      variables in the integral except the variable of
                      integration.  (Unless another integral is in buffer1).
                        Also, the term may be undefined; you may have
                      to make an assumption.
                   */
                    { if( !contains2(s,INTEGRAL,2) ) /* the most usual case */
                     /* note, DEFINITE integrals are ok; we're checking
                        only for INDEFINITE integrals */
                         { err = get_polyvaldomainflag() ? check1(domain(s)) : 0;
                           if(err==0)  /* inferred or assumed it */
                              { actuallycancel(buffer1,k,i,j,buffer2);
                                *m = k-2;
                                *cancelled = s;
                                return 0;
                              }
                         }
                      else  /* s did contain an indefinite INTEGRAL */
                         { term temp;
                           err = cancel_integral(buffer1,k,i,j,&temp);
                           if(err)
                              { *m = k;
                                return 1;
                              }
                           if(FUNCTOR(temp)=='+')
                              { for(q=0;q<ARITY(temp);q++)
                                   buffer2[q] = ARG(q,temp);
                                *m = ARITY(temp);
                              }
                           else
                              { buffer2[0] = temp;
                                *m = 1;
                              }
                           *cancelled = s;
                           return 0;
                         }
                    }  /* disposing of the apparent cancellation buffer1[i],buffer1[j] */
                       /* if we get here, it was an illegal cancellation */
               } /* close the j-loop */
          }   /* close the 'if' on buffer[i] */
     }  /* close the i-loop */
         /* if we get here, there was no cancellation */
  *m = k;
  return 1;
}
/*___________________________________________________________________*/
static int cancel_integral(term *buffer,int k, int i,int j,term *ans)
/* buffer is an array of terms of dimension k (originally the args of a sum).
buffer[i] and buffer[j] are two terms which apparently cancel,
i.e. are negations of each other, but they contain an indefinite
integral, so in cancelling them, we may have to introduce a constant of
integration (if there are no other integrals in buffer1);
and the cancellation can only be performed if
(a) the term to be cancelled is the integral itself
(b) the term to be cancelled is a product, one of whose factors is the
    integral.
*ans is the result of performing the cancellation.
Return 0 for success; return 1 if the integral is nested too deeply;
you can only cancel an integral or a product one of whose factors is
an integral; you can't e.g. cancel a product of sums one of whose
summands is an integral.  I don't think such terms can ever arise anyway.
*/
{ term s,temp,newterm,q;
  int p,cneeded,flag;
  int l,ll,max,min;
  min = ((i<j) ? i: j);
  max = ((i<j) ? j: i);
  if(FUNCTOR(buffer[i])== '-')
    s = ARG(0,buffer[i]);
  else
    { s = ARG(0,buffer[j]);
      assert(FUNCTOR(buffer[j])== '-');
    }
  if(k==2 && FUNCTOR(s)==INTEGRAL)  /* two cancelling integrals */
       { *ans = constant_of_integration(ARG(0,s),ARG(1,s));
         return 0;
       }
  /* First determine whether or not a constant of integration will
  be required. */
  for(l=0;l<k;l++)
     { if(l==i || l==j)
          continue;
       temp = buffer[l];
       if(contains2(temp,INTEGRAL,2))
          break;
     }
  if(l==k)
      cneeded = 1;   /* constant of integration needed */
  else
      cneeded = 0;

  if(!cneeded)
    { if(k==3)
        { if(i==0)
             l = j==1 ? 2 : 1;
          else if (i==1)
             l = j==0 ? 2 : 0;
          else if (i==2)
             l = j==0 ? 1 : 0;
          *ans = buffer[l];
          return 0;
        }
      assert(k>=4);
      *ans = make_term('+',(unsigned short)(k-2));
      ll=0;
      for(l=0;l<k;l++)
        { if(l==i || l==j)
             continue;
          ARGREP(*ans,ll,buffer[l]);
          ++ll;
        }
      return 0;
    }
  while(
        (FRACTION(s) && constant(ARG(1,s))) ||
        NEGATIVE(s)
       )
     s = ARG(0,s);
  /* Now we need a constant of integration */
  if(FUNCTOR(s)==INTEGRAL)
     /*  integral(u,x) - integral(u,x) = c  */
     { *ans = make_term('+',(unsigned short)(k-1));  /* arity is at least two since k==2 is handled above */
       q = constant_of_integration(ARG(0,s),ARG(1,s));
       ARGREP(*ans,min,q);
       for(p=0;p<min;p++)
         ARGREP(*ans,p,buffer[p]);
       for(p=min+1;p<max;p++)
         ARGREP(*ans,p,buffer[p]);
       for(p=max; p<k-1;p++)
         ARGREP(*ans,p,buffer[p+1]);
       return 0;
     }
  if(FUNCTOR(s) != '*')
     assert(0);
  /* indefinite integrals can only be in sums and products, or possibly
     numerators of fractions with constant denoms, but we took care of
     that above. */
  /*  y integral(u,x) - y integral(u,x) = yc */
  newterm = make_term('*',ARITY(s));
  flag=0;
  for(p=0;p<ARITY(s);p++)
     { temp = ARG(p,s);
       if(FUNCTOR(temp)==INTEGRAL && flag==0)
         { q = constant_of_integration(ARG(0,temp),ARG(1,temp));
           ARGREP(newterm,p,q);
           flag = 1;
         }
       else
          ARGREP(newterm,p,ARG(p,s));
     }
  if(flag == 0)
     return 1;   /* failure, integrals nested too deeply */
  if(k==2)  /* cancelling products of integrals */
     { *ans = newterm;
       return 0;
     }
  *ans = make_term('+',(unsigned short)(k-1));
  ARGREP(*ans,min,newterm);
  for(p=0;p<min;p++)
     ARGREP(*ans,p,buffer[p]);
  for(p=min+1;p<max;p++)
     ARGREP(*ans,p,buffer[p]);
  for(p=max; p<k-1;p++)
     ARGREP(*ans,p,buffer[p+1]);
  return 0;
}

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