Sindbad~EG File Manager

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

/*  trig_squares, trig_sum operators
M. Beeson, for MathXpert
1.13.91  original date
5.12.98 last modified
*/

#define ALGEBRA_DLL
#include <string.h>
#include "globals.h"
#include "ops.h"
#include "trig.h"
#include "match.h"
#include "order.h"
#include "cancel.h"
#include "prover.h"
#include "trigsq.h"
#include "symbols.h"
#include "calc.h"
#include "errbuf.h"
#include "pvalaux.h"  /* isinteger */
#include "pathtail.h" /* set_pathtail, pathncopy, etc */
#include "autosimp.h" /* SetShowStepOperation */
#include "tdefn.h"
#include "cflags.h"

static void check_periodic(term t);
static void check_complementary(term t);

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsquare1(term t, term arg, term *next, char *reason)
/* sin^2 a + cos^2 a = 1 */
{ term lhs,a,b,c,temp,u,v;
  int i,j,k,err;
  unsigned short n;
  unsigned short path[5];
  if(FUNCTOR(t) != '+')
     return 1;
  lhs = sum(make_power(sin1(var0),two),make_power(cos1(var0),two));
  err = match(t,lhs,one,&a,next);   /* instantiate a and *next */
  if(!err)
     { HIGHLIGHT(*next);
       strcpy(reason,"$sin^2 a + cos^2 a = 1$");
       return 0;
     }
  /* But don't give up; work on x sin^2 x + x cos ^2 x too */
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(!contains(ARG(i,t),SIN))
          continue;
       for(j=0;j<n;j++)
          { if(j == i || !contains(ARG(j,t),COS))
               continue;
            u = sum(ARG(i,t),ARG(j,t));
            if(!content_factor(u,&c,&b) &&
               !match(b,lhs,one,&a,&temp)
              )
               { if(j == i+1 && get_mathmode() == AUTOMODE)
                    { /* imitate content-factoring for ShowStep */
                      SetShowStepOperation(contentfactor);
                      if(n == 2)
                          { *next = product(c,b);
                            HIGHLIGHT(*next);
                            strcpy(reason, "ab+ac = a(b+c)");
                            return 0;
                          }
                      *next= make_term('+',(unsigned short)(n-1));
                      for(k=0;k<n-1;k++)
                         { if(k==i)
                              { ARGREP(*next,k, product(c,b));
                                HIGHLIGHT(ARG(k,*next));
                              }
                           else if(k<i)
                              ARGREP(*next,k,ARG(k,t));
                           else
                              ARGREP(*next,k,ARG(k+1,t));
                         }
                      path[0] = '+';
                      path[1] = i+1;
                      path[2] = SUBRANGE;
                      path[3] = j+1;
                      path[4] = 0;
                      set_pathtail(path);
                      strcpy(reason, "ab+ac = a(b+c)");
                      return 0;
                    }
                 v = NEGATIVE(temp) ?
                        tnegate(product(c,ARG(0,temp))) :
                        NEGATIVE(c) ?
                           product(ARG(0,c),temp) :
                           product(c,temp);
                 if(n == 2)
                    { *next = v;
                      HIGHLIGHT(*next);
                      strcpy(reason,"$sin^2 a + cos^2 a = 1$");
                      return 0;
                    }
                 *next = make_term('+',(unsigned short)(n-1));
                 if(j < i)
                    { k=i;
                      i=j;
                      j=k;
                    }
                 for(k=0;k<n-1;k++)
                    ARGREP(*next,k,k<i ? ARG(k,t) : k == i ? v : k < j ? ARG(k,t) : ARG(k+1,t));
                 HIGHLIGHT(ARG(i,*next));
                 strcpy(reason,"$sin^2 a + cos^2 a = 1$");
                 return 0;
               }
          }
     }
  destroy_term(lhs);
  return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsquare2(term t, term arg, term *next, char *reason)
/* 1 - sin^2 a = cos^2 a */
{ term lhs,rhs,a;
  unsigned short path[11];
  int i,j;
  int err;
  if(FRACTION(t) && get_mathmode() == AUTOMODE)
     { term x;
       int whicharg;
       term newnum,newdenom;;
       err = sq_aux(ARG(1,t),COS,&x,&whicharg);
       if(!err)
          { err = sinsquare2(ARG(0,t),arg,&newnum,reason);
            if(err)
               return 1;
            *next = make_fraction(newnum,ARG(1,t));
            path[0] = '/';
            path[1] = 1;
            path[2] = 0;
            if(FUNCTOR(ARG(0,t))=='^' || FUNCTOR(ARG(0,t)) == '*')
               pathcat(path,get_pathtail());
            set_pathtail(path);
            goto out;
          }
       err = sq_aux(ARG(0,t),COS,&x,&whicharg);
       if(!err)
          { err = sinsquare2(ARG(1,t),arg,&newdenom,reason);
            if(err)
               return 1;
            *next = make_fraction(ARG(0,t),newdenom);;
            path[0] = '/';
            path[1] = 2;
            path[2] = 0;
            if(FUNCTOR(ARG(1,t))== '^' || FUNCTOR(ARG(1,t)) == '*')
                pathcat(path,get_pathtail());
            set_pathtail(path);
            goto out;
          }
       return 1;
     }
  if(FUNCTOR(t) == '^' && get_mathmode() == AUTOMODE)
     { term temp;
       if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
          return 1;
       err = sinsquare2(ARG(0,t),arg,&temp,reason);
       if(err)
          return 1;
       *next = make_power(temp,ARG(1,t));
       path[0] = '^';
       path[1] = 1;
       path[2] = 0;
       set_pathtail(path);
       goto out;
     }
  if(FUNCTOR(t) == '*' && get_mathmode() == AUTOMODE)
     { unsigned short  n = ARITY(t);
       term u,temp;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) != '^' && FUNCTOR(u) != '+')
               continue;
            err = sinsquare2(u,arg,&temp,reason);
            if(!err)
               { path[0] = '*';
                 path[1] = i+1;
                 path[2] = 0;
                 if(FUNCTOR(u) == '^')
                    pathcat(path, get_pathtail());
                 set_pathtail(path);
                 break;
               }
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(j=0;j<n;j++)
          ARGREP(*next,j,i==j ? temp : ARG(j,t));
       goto out;
     }
  lhs = sum(one,tnegate(make_power(sin1(var0),two)));
  rhs = make_power(cos1(var0),two);
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       destroy_term(rhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$1 - sin^2 a = cos^2 a$");
  out:
     release(cancelop);  /* perhaps inhibited by trigrationalizedenom1 or trigrationalizedenom2 */
     release(polyvalop);
     release(cancelgcd);
     release(differenceofsquares);
     return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsquare3(term t, term arg, term *next, char *reason)
/* 1 - cos^2 a = sin^2 a */
{ term lhs,rhs,a;
  int err,i,j;
  unsigned short path[11];
  if(FRACTION(t) && get_mathmode() == AUTOMODE)
     { term x;
       int whicharg;
       term newnum,newdenom;;
       err = sq_aux(ARG(1,t),SIN,&x,&whicharg);
       if(!err)
          { err = sinsquare3(ARG(0,t),arg,&newnum,reason);
            if(err)
               return 1;
            *next = make_fraction(newnum,ARG(1,t));
            path[0] = '/';
            path[1] = 1;
            path[2] = 0;
            if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
               pathcat(path, get_pathtail());
            set_pathtail(path);
            goto out;
          }
       err = sq_aux(ARG(0,t),SIN,&x,&whicharg);
       if(!err)
          { err = sinsquare3(ARG(1,t),arg,&newdenom,reason);
            if(err)
               return 1;
            *next = make_fraction(ARG(0,t),newdenom);
            path[0] = '/';
            path[1] = 2;
            path[2] = 0;
            if(FUNCTOR(ARG(1,t)) == '^' || FUNCTOR(ARG(1,t)) == '*')
               pathcat(path,get_pathtail());
            set_pathtail(path);
            goto out;
          }
       return 1;
     }
  if(FUNCTOR(t) == '^' && get_mathmode() == AUTOMODE)
     { term temp;
       if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
          return 1;
       err = sinsquare3(ARG(0,t),arg,&temp,reason);
       if(err)
          return 1;
       *next = make_power(temp,ARG(1,t));
       path[0] = '^';
       path[1] = 1;
       path[2] = 0;
       set_pathtail(path);
       goto out;
     }
  if(FUNCTOR(t) == '*' && get_mathmode() == AUTOMODE)
     { unsigned short  n = ARITY(t);
       term u,temp;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) != '^' && FUNCTOR(u) != '+')
               continue;
            err = sinsquare3(u,arg,&temp,reason);
            if(!err)
               { path[0] = '*';
                 path[1] = i+1;
                 path[2] = 0;
                 if(FUNCTOR(u) == '^')
                    pathcat(path, get_pathtail());
                 set_pathtail(path);
                 break;
               }
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(j=0;j<n;j++)
          ARGREP(*next,j,i==j ? temp : ARG(j,t));
       goto out;
     }
  lhs = sum(one,tnegate(make_power(cos1(var0),two)));
  rhs = make_power(sin1(var0),two);
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$1 - cos^2 a = sin^2 a$");
  out:
     release(cancelop);  /* perhaps inhibited by trigrationalizedenom1 or trigrationalizedenom2 */
     release(polyvalop);
     release(cancelgcd);
     release(differenceofsquares);
     return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int secsqminustansq(term t, term arg, term *next, char *reason)
/* sec^2 a - tan^2 a = 1  */
{ term lhs,rhs,a;
  int err;
  lhs = sum(make_power(sec1(var0),two),tnegate(make_power(tan1(var0),two)));
  rhs = one;
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$sec^2 a - tan^2 a = 1$");
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tansquare1(term t, term arg, term *next, char *reason)
/* tan^2 a + 1 = sec^2 a */
{ term lhs,rhs,a;
  int err;
  lhs = sum(make_power(tan1(var0),two),one);
  rhs = make_power(sec1(var0),two);
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$tan^2 a + 1 = sec^2 a$");
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tansquare2(term t, term arg, term *next, char *reason)
/* sec^2 a - 1 = tan^2 a */
{ term lhs,rhs,a;
  int err;
  unsigned short path[11];
  if(FRACTION(t) && get_mathmode() == AUTOMODE)
     { term x;
       int whicharg;
       term newnum,newdenom;;
       err = sq_aux(ARG(1,t),TAN,&x,&whicharg);
       if(!err)
          { err = tansquare2(ARG(0,t),arg,&newnum,reason);
            if(err)
               return 1;
            *next = make_fraction(newnum,ARG(1,t));
            path[0] = '/';
            path[1] = 1;
            path[2] = 0;
            if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
               pathcat(path,get_pathtail());
            set_pathtail(path);
            return 0;
          }
       err = sq_aux(ARG(0,t),TAN,&x,&whicharg);
       if(!err)
          { err = tansquare2(ARG(1,t),arg,&newdenom,reason);
            if(err)
               return 1;
            *next = make_fraction(ARG(0,t),newdenom);
            path[0] = '/';
            path[1] = 2;
            path[2] = 0;
            if(FUNCTOR(ARG(1,t)) == '^' || FUNCTOR(ARG(1,t)) == '*')
               pathcat(path, get_pathtail());
            set_pathtail(path);
            return 0;
          }
       return 1;
     }
  if(FUNCTOR(t) == '^' && get_mathmode() == AUTOMODE)
     { term temp;
       if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
          return 1;
       err = tansquare2(ARG(0,t),arg,&temp,reason);
       if(err)
          return 1;
       *next = make_power(temp,ARG(1,t));
       path[0] = '^';
       path[1] = 1;
       path[2] = 0;
       set_pathtail(path);
       return 0;
     }
  if(FUNCTOR(t) == '*' && get_mathmode() == AUTOMODE)
     { int i,j;
       unsigned short  n = ARITY(t);
       term u,temp;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) != '^' && FUNCTOR(u) != '+')
               continue;
            err = tansquare2(u,arg,&temp,reason);
            if(!err)
               { path[0] = '*';
                 path[1] = i+1;
                 path[2] = 0;
                 if(FUNCTOR(u) == '^')
                    pathcat(path, get_pathtail());
                 break;
               }
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(j=0;j<n;j++)
          ARGREP(*next,j,i==j ? temp : ARG(j,t));
       return 0;
     }
  lhs = sum(make_power(sec1(var0),two),minusone);
  rhs = make_power(tan1(var0),two);
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$sec^2 a - 1 = tan^2 a$");
  return 0;
}
/*___________________________________________________________*/
int sq_aux(term u, unsigned short  f, term *x, int *whicharg)
/*  Does u equal f^2(...) or contain it as a
factor?  if so instantiate *x to ... and return 0.  If not return 1.
If u is a product, return in *whicharg the index of the arg which
was found to contain f^2.  Otherwise *whicharg is garbage. */

{ unsigned short  n;
  int i;
  term v;
  if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == f && equals(ARG(1,u),two))
     { *x = ARG(0,ARG(0,u));
       return 0;
     }
  if(FUNCTOR(u) != '*')
     return 1;
  n = ARITY(u);
  for(i=0;i<n;i++)
     { v = ARG(i,u);
       if(FUNCTOR(v) == '^' && FUNCTOR(ARG(0,v)) == f && equals(ARG(1,v),two))
          { *x = ARG(0,ARG(0,v));
            *whicharg = i;
            return 0;
          }
     }
  return 1;
}
/*___________________________________________________________*/
static int sq_aux2(term u, term x, unsigned short  g)
/* does 1-g(x) or 1+g(x) occur as u or as a factor of u?
   Or 1-g^2(x), or g^2x -1?
   Or g(x) � 1? Or a power of any of those things?
   If so return 0, if not return 1. */
{ term v,w;
  unsigned short  n;
  int i,err;
  if(FUNCTOR(u) == '+' && ARITY(u)==2)
     { v = ARG(0,u);
       w = ARG(1,u);
       if(NEGATIVE(v))
          v = ARG(0,v);
       if(NEGATIVE(w))
          w = ARG(0,w);
       if(FUNCTOR(v) == g && ONE(w))
          return 0;
       if(FUNCTOR(w) == g && ONE(v))
          return 0;
       return 1;
     }
  if(FUNCTOR(u) == '^')
     return sq_aux2(ARG(0,u),x,g);
  if(FUNCTOR(u) != '*')
     return 1;
  n = ARITY(u);
  for(i=0;i<n;i++)
     { err = sq_aux2(ARG(i,u),x,g);
       if(!err)
          return 0;
     }
  return 1;
}
/*___________________________________________________________*/
int sqinfract(term t, unsigned short f, term *next, char *reason)
/* f is COS,SIN, TAN,or COT; t is a fraction.
Use cossqtosinsq (if f==COS)
    sinsqtocossq (if f == SIN)
    cotsqtocscsq (if f == COT)
    tansqtoseqsq (if f == TAN)

on the numerator or denom of t, if a cancellation
will later be possible.  Example: (1-sin x)/cos^2 x.
Another example: (1-sin x)^2/cos^2 x.   */

{ term num = ARG(0,t);
  term denom = ARG(1,t);
  term x,temp,newnum,newdenom;
  int i,j,err;
  actualop op;
  unsigned short path[5];
  unsigned h =  f==SIN ? COS : f == TAN ? SEC : f == COT ? CSC : SIN;
  unsigned short g = (unsigned short) h;
  /* comments will suppose f == SIN for simplicity, so g == COS */
  err = sq_aux(denom,f,&x,&i);  /* does cos^2 occur there? */
  if(err)
     { err = sq_aux(num,f,&x,&i);
       if(err)
          return 1;
       err = sq_aux2(denom,x,g);  /* does 1-sin x or 1+sin x occur? */
                                  /* or a power of it?  */
       if(err)
          return 1;
       if(FUNCTOR(num) == '*')
          { switch(f)
               { case COS:
                    op = cossqtosinsq;
                    break;
                 case SIN:
                    op = sinsqtocossq;
                    break;
                 case COT:
                    op = cotsqtocscsq;
                    break;
                 case TAN:
                    op = tansqtosecsq;
                    break;
                 default:
                    return 1;
               }
            err = (*op)(ARG(i,num),zero,&temp,reason);
            if(err)
               return 1;
            path[0] = '/';
            path[1] = 1;
            path[2] = '*';
            path[3] = (unsigned short)(i+1);
            path[4] = 0;
            set_pathtail(path);
            SetShowStepOperation(op);
            newnum = make_term('*',ARITY(num));
            for(j=0;j<ARITY(num);j++)
               ARGREP(newnum,j,j==i ? temp : ARG(j,num));
          }
       else
          { switch(f)
               { case COS:
                    op = cossqtosinsq;
                    break;
                 case SIN:
                    op = sinsqtocossq;
                    break;
                 case COT:
                    op = cotsqtocscsq;
                    break;
                 case TAN:
                    op = tansqtosecsq;
                    break;
                 default:
                    return 1;
               }
            err = (*op)(num,zero,&newnum,reason);
            if(err)
               return 1;
            path[0] = '/';
            path[1] = 1;
            path[2] = 0;
            set_pathtail(path);
            SetShowStepOperation(op);
          }
       *next = make_fraction(newnum,denom);
       return 0;
     }
  err = sq_aux2(num,x,g);  /* does 1-sin x or 1+sin x occur? */
  if(err)
     return 1;
  if(FUNCTOR(denom) == '*')
     { switch(f)
          { case COS:
               op = cossqtosinsq;
               break;
            case SIN:
               op = sinsqtocossq;
               break;
            case COT:
               op = cotsqtocscsq;
               break;
            case TAN:
               op = tansqtosecsq;
               break;
            default:
               return 1;
          }
       err = (*op)(ARG(i,denom),zero,&temp,reason);
       if(err)
          return 1;
       newdenom = make_term('*',ARITY(denom));
       path[0] = '/';
       path[1] = 2;
       path[2] = '*';
       path[3] = (unsigned short) (i+1);
       path[4] = 0;
       set_pathtail(path);
       SetShowStepOperation(op);
       for(j=0;j<ARITY(denom);j++)
          ARGREP(newdenom,j,j==i ? temp : ARG(j,denom));
     }
  else
     { switch(f)
          { case COS:
               op = cossqtosinsq;
               break;
            case SIN:
               op = sinsqtocossq;
               break;
            case COT:
               op = cotsqtocscsq;
               break;
            case TAN:
               op = tansqtosecsq;
               break;
            default:
               return 1;
          }
       err = (*op)(denom,zero,&newdenom,reason);
       if(err)
          return 1;
       path[0] = '/';
       path[1] = 2;
       path[2] = 0;
       set_pathtail(path);
       SetShowStepOperation(op);
     }
  *next = make_fraction(num,newdenom);
  release(cancelgcd);  /* in case inhibited by trigrationalize1 etc. */
  return 0;
}

/*___________________________________________________________*/
MEXPORT_ALGEBRA int cossqtosinsq(term t, term arg, term *next, char *reason)
/* cos^2 u = 1 - sin^2 u.  But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
It also works on a quotient, for example (1-sin x)/cos^2 x, if a
cancellation will be possible later.
*/

{ term u,v,temp,c,s;
  int i,j,err;
  int powerflag;
  unsigned short  n;
  unsigned short path[11];
  int success = 0;
  if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
     return sqinfract(t,COS,next,reason);
  if(FUNCTOR(t) == '=')
     { if(FUNCTOR(ARG(0,t)) == '^' &&
          FUNCTOR(ARG(0,ARG(0,t))) == COS &&
          iseven(ARG(1,ARG(0,t)))
         )
          { err = cossqtosinsq(ARG(0,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(temp,ARG(1,t));
            path[0] = '=';
            path[1] = 1;
            path[2] = 0;
            set_pathtail(path);
            return 0;
          }
       else if(FUNCTOR(ARG(1,t)) == '^' &&
               FUNCTOR(ARG(0,ARG(1,t))) == COS &&
               iseven(ARG(1,ARG(1,t)))
              )
          { err = cossqtosinsq(ARG(1,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(ARG(0,t),temp);
            path[0] = '=';
            path[1] = 2;
            path[2] = 0;
            set_pathtail(path);
            return 0;
         }
     }
  if(FUNCTOR(t)== '+' && contains(t,COS))
     { n = ARITY(t);
       v = make_term('+',n);
       powerflag = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            err = cossqtosinsq(u,arg,&temp,reason);
            if(!err)
               { ARGREP(v,i,temp);
                 success = 1;
                 path[0] = '+';
                 path[1] = i+1;
                 path[2] = 0;
                 if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
                    pathcat(path,get_pathtail());
                 set_pathtail(path);
                 /* Now set powerflag if we don't want to call polyval on the result
                    because that will produce a too-large step for a student */
                 temp = NEGATIVE(u) ? ARG(0,u) : u;
                 if(FUNCTOR(temp) == '*')
                    { ratpart2(temp,&c,&s);
                      temp = s;
                    }
                 if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
                    powerflag = 1;
                 if(FUNCTOR(temp) == '*')
                    powerflag = 1;
                 PROTECT(ARG(i,v));  /* so the new 1-sin^2 doesn't just get
                                        rewritten as cos^2 again before it's
                                        expanded.  Since expand works on the
                                        sum the PROTECTion won't stop it. */
               }
            else
               ARGREP(v,i,u);
          }
       if(success)
          { if(powerflag)
               copy(v,next); /* without simplifying */
            else
               polyval(v,next);
            return 0;
          }
       return 1;
     }
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == COS)
               { err = cossqtosinsq(u,arg,&temp,reason);
                 if(!err)
                    { path[0] = '*';
                      path[1] = i+1;
                      path[2] = 0;
                      set_pathtail(path);
                      break;
                    }
               }
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(j=0;j<n;j++)
          { if(j==i)
               ARGREP(*next,j,temp);
            else
               ARGREP(*next,j,ARG(j,t));
          }
       return 0;
     }
  if(FUNCTOR(t) == '-')
     { err = cossqtosinsq(ARG(0,t),arg,&temp,reason);
       if(err)
          return 1;
       *next = tnegate(temp);
       path[0] = '-';
       path[1] = 1;
       path[2] = 0;
       if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
          pathcat(path,get_pathtail());
       set_pathtail(path);
       return 0;
     }
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != COS)
     return 1;
  u = ARG(0,ARG(0,t));
  if(!equals(ARG(1,t),two))
     { err = cancel(ARG(1,t),two,&temp,&v);
       if(err)
         return 1;
       *next = make_power(sum(one,tnegate(make_power(sin1(u),two))),v);
     }
  else  /* exponent is two */
     *next = sum(one,tnegate(make_power(sin1(u),two)));
  HIGHLIGHT(*next);
  strcpy(reason,"$cos^2 u = 1 - sin^2 u$");
  release(cancelgcd);  /* in case inhibited by trigrationalize1 etc. */
  return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int sinsqtocossq(term t, term arg, term *next, char *reason)
/* sin^2 u = 1 - cos^2 u.  But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
*/

{ term u,v,temp,c,s;
  int i,j,err;
  int powerflag;
  unsigned short  n;
  int success = 0;
  unsigned short path[11];
  if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
     return sqinfract(t,SIN,next,reason);
  if(FUNCTOR(t) == '=')
     { if(FUNCTOR(ARG(0,t)) == '^' &&
          FUNCTOR(ARG(0,ARG(0,t))) == SIN &&
          iseven(ARG(1,ARG(0,t)))
         )
          { err = sinsqtocossq(ARG(0,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(temp,ARG(1,t));
            path[0] = '=';
            path[1] = 1;
            path[2] = 0;
            set_pathtail(path);
            return 0;
          }
       else if(FUNCTOR(ARG(1,t)) == '^' &&
               FUNCTOR(ARG(0,ARG(1,t))) == SIN &&
               iseven(ARG(1,ARG(1,t)))
              )
          { err = sinsqtocossq(ARG(1,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(ARG(0,t),temp);
            path[0] = '=';
            path[1] = 2;
            path[2] = 0;
            set_pathtail(path);
            return 0;
         }
     }

  if(FUNCTOR(t)== '+' && contains(t,SIN))
     { n = ARITY(t);
       v = make_term('+',n);
       powerflag = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            err = sinsqtocossq(u,arg,&temp,reason);
            if(!err)
               { ARGREP(v,i,temp);
                 success = 1;
                 path[0] = '+';
                 path[1] = i+1;
                 path[2] = 0;
                 if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
                    pathcat(path,get_pathtail());
                 set_pathtail(path);
                 /* Now set powerflag if we don't want to call polyval on the result
                    because that will produce a too-large step for a student */
                 temp = NEGATIVE(u) ? ARG(0,u) : u;
                 if(FUNCTOR(temp) == '*')
                    { ratpart2(temp,&c,&s);
                      temp = s;
                    }
                 if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
                    powerflag = 1;
                 if(FUNCTOR(temp) == '*')
                    powerflag = 1;
                 PROTECT(ARG(i,v));  /* so the new 1-cos^2 doesn't just get
                                        rewritten as sin^2 again before it's
                                        expanded.  Since expand works on the
                                        sum the PROTECTion won't stop it. */
               }
            else
               ARGREP(v,i,u);
          }
       if(success)
          { if(powerflag)
                copy(v,next);
            else
               polyval(v,next);
            return 0;
          }
       return 1;
     }
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == SIN)
               { err = sinsqtocossq(u,arg,&temp,reason);
                 if(!err)
                    { path[0] = '*';
                      path[1] = i+1;
                      path[2] = 0;
                      set_pathtail(path);
                      break;
                    }
               }
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(j=0;j<n;j++)
          { if(j==i)
               ARGREP(*next,j,temp);
            else
               ARGREP(*next,j,ARG(j,t));
          }
       return 0;
     }
  if(FUNCTOR(t) == '-')
     { err = sinsqtocossq(ARG(0,t),arg,&temp,reason);
       if(err)
          return 1;
       *next = tnegate(temp);
       path[0] = '-';
       path[1] = 1;
       path[2] = 0;
       if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
          pathcat(path,get_pathtail());
       set_pathtail(path);
       return 0;
     }
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != SIN)
     return 1;
  u = ARG(0,ARG(0,t));
  if(!equals(ARG(1,t),two))
     { err = cancel(ARG(1,t),two,&temp,&v);
       if(err)
         return 1;
       *next = make_power(sum(one,tnegate(make_power(cos1(u),two))),v);
     }
  else  /* exponentis two */
     *next = sum(one,tnegate(make_power(cos1(u),two)));
  HIGHLIGHT(*next);
  strcpy(reason,"$sin^2 u = 1 - cos^2 u$");
  release(cancelgcd);  /* in case inhibited by trigrationalize1 etc. */
  return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int tansqtosecsq(term t, term arg, term *next, char *reason)
/* tan^2 u = sec^2 u - 1.  But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
*/

{ term u,v,temp,c,s;
  int i,j,err,powerflag;
  unsigned short  n;
  unsigned short path[11];
  int success = 0;
  if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
     return sqinfract(t,TAN,next,reason);
  if(FUNCTOR(t) == '=')
     { if(FUNCTOR(ARG(0,t)) == '^' &&
          FUNCTOR(ARG(0,ARG(0,t))) == TAN &&
          iseven(ARG(1,ARG(0,t)))
         )
          { err = tansqtosecsq(ARG(0,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(temp,ARG(1,t));
            path[0] = '=';
            path[1] = 1;
            path[2] = 0;
            set_pathtail(path);
            return 0;
          }
       else if(FUNCTOR(ARG(1,t)) == '^' &&
               FUNCTOR(ARG(0,ARG(1,t))) == TAN &&
               iseven(ARG(1,ARG(1,t)))
              )
          { err = tansqtosecsq(ARG(1,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(ARG(0,t),temp);
            path[0] = '=';
            path[1] = 2;
            path[2] = 0;
            set_pathtail(path);
            return 0;
         }
     }
  if(FUNCTOR(t)== '+' && contains(t,TAN))
     { n = ARITY(t);
       v = make_term('+',n);
       powerflag = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            err = tansqtosecsq(u,arg,&temp,reason);
            if(!err)
               { ARGREP(v,i,temp);
                 success = 1;
                 path[0] = '+';
                 path[1] = i+1;
                 path[2] = 0;
                 if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
                    pathcat(path,get_pathtail());
                 set_pathtail(path);
                 /* Now set powerflag if we don't want to call polyval on the result
                    because that will produce a too-large step for a student */
                 temp = NEGATIVE(u) ? ARG(0,u) : u;
                 if(FUNCTOR(temp) == '*')
                    { ratpart2(temp,&c,&s);
                      temp = s;
                    }
                 if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
                    powerflag = 1;
                 if(FUNCTOR(temp) == '*')
                    powerflag = 1;
                 PROTECT(ARG(i,v));  /* so the new sec^2-1 doesn't just get
                                        rewritten as tan^2 again before it's
                                        expanded.  Since expand works on the
                                        sum the PROTECTion won't stop it. */
               }
            else
               ARGREP(v,i,u);
          }
       if(success)
          { if(powerflag)
                copy(v,next);
            else
               polyval(v,next);
            return 0;
          }
       return 1;
     }
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == TAN)
               { err = tansqtosecsq(u,arg,&temp,reason);
                 if(!err)
                    { path[0] = '*';
                      path[1] = i+1;
                      path[2] = 0;
                      set_pathtail(path);
                      break;
                    }
               }
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(j=0;j<n;j++)
          { if(j==i)
               ARGREP(*next,j,temp);
            else
               ARGREP(*next,j,ARG(j,t));
          }
       return 0;
     }
  if(FUNCTOR(t) == '-')
     { err = tansqtosecsq(ARG(0,t),arg,&temp,reason);
       if(err)
          return 1;
       *next = tnegate(temp);
       path[0] = '-';
       path[1] = 1;
       path[2] = 0;
       if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
          pathcat(path,get_pathtail());
       set_pathtail(path);
       return 0;
     }
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != TAN)
     return 1;
  u = ARG(0,ARG(0,t));
  if(!equals(ARG(1,t),two))
     { err = cancel(ARG(1,t),two,&temp,&v);
       if(err)
         return 1;
       *next = make_power(sum(make_power(sec1(u),two),minusone),v);
     }
  else  /* exponentis two */
     *next = sum(make_power(sec1(u),two),minusone);
  HIGHLIGHT(*next);
  strcpy(reason,"$tan^2 u = sec^2 u - 1$");
  return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int secsqtotansq(term t, term arg, term *next, char *reason)
/* sec^2 u = tan^2 u + 1.  But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
*/

{ term u,v,temp,c,s;
  int i,j,err,powerflag;
  unsigned short path[11];
  unsigned short n;
  int success = 0;
  if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
     return sqinfract(t,SEC,next,reason);
  if(FUNCTOR(t) == '=')
     { if(FUNCTOR(ARG(0,t)) == '^' &&
          FUNCTOR(ARG(0,ARG(0,t))) == SEC &&
          iseven(ARG(1,ARG(0,t)))
         )
          { err = secsqtotansq(ARG(0,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(temp,ARG(1,t));
            path[0] = '=';
            path[1] = 1;
            path[2] = 0;
            set_pathtail(path);
            return 0;
          }
       else if(FUNCTOR(ARG(1,t)) == '^' &&
               FUNCTOR(ARG(0,ARG(1,t))) == TAN &&
               iseven(ARG(1,ARG(1,t)))
              )
          { err = secsqtotansq(ARG(1,t),arg,&temp,reason);
            if(err)
               return 1;
            *next = equation(ARG(0,t),temp);
            path[0] = '=';
            path[1] = 2;
            path[2] = 0;
            set_pathtail(path);
            return 0;
         }
     }
  if(FUNCTOR(t)== '+' && contains(t,SEC))
     { n = ARITY(t);
       v = make_term('+',n);
       powerflag = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            err = secsqtotansq(u,arg,&temp,reason);
            if(!err)
               { ARGREP(v,i,temp);
                 success = 1;
                 path[0] = '+';
                 path[1] = i+1;
                 path[2] = 0;
                 if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
                    pathcat(path,get_pathtail());
                 set_pathtail(path);
                 /* Now set powerflag if we don't want to call polyval on the result
                    because that will produce a too-large step for a student */
                 temp = NEGATIVE(u) ? ARG(0,u) : u;
                 if(FUNCTOR(temp) == '*')
                    { ratpart2(temp,&c,&s);
                      temp = s;
                    }
                 if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
                    powerflag = 1;
                 if(FUNCTOR(temp) == '*')
                    powerflag = 1;
                 PROTECT(ARG(i,v));  /* so the new tan^2-1 doesn't just get
                                        rewritten as sec^2 again before it's
                                        expanded.  Since expand works on the
                                        sum the PROTECTion won't stop it. */
               }
            else
               ARGREP(v,i,u);
          }
       if(success)
          { if(powerflag)
                copy(v,next);
            else
               polyval(v,next);
            return 0;
          }
       return 1;
     }
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == SEC)
               { err = secsqtotansq(u,arg,&temp,reason);
                 if(!err)
                    { path[0] = '*';
                      path[1] = i+1;
                      path[2] = 0;
                      set_pathtail(path);
                      break;
                    }
               }
          }
       if(i==n)
          return 1;
       *next = make_term('*',n);
       for(j=0;j<n;j++)
          { if(j==i)
               ARGREP(*next,j,temp);
            else
               ARGREP(*next,j,ARG(j,t));
          }
       return 0;
     }
  if(FUNCTOR(t) == '-')
     { err = secsqtotansq(ARG(0,t),arg,&temp,reason);
       if(err)
          return 1;
       *next = tnegate(temp);
       path[0] = '-';
       path[1] = 1;
       path[2] = 0;
       if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
          pathcat(path,get_pathtail());
       set_pathtail(path);
       return 0;
     }
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != SEC)
     return 1;
  u = ARG(0,ARG(0,t));
  if(!equals(ARG(1,t),two))
     { err = cancel(ARG(1,t),two,&temp,&v);
       if(err)
         return 1;
       *next = make_power(sum(make_power(tan1(u),two),one),v);
     }
  else  /* exponentis two */
     *next = sum(make_power(tan1(u),two),one);
  HIGHLIGHT(*next);
  strcpy(reason,"$sec^2 u = tan^2 u + 1$");
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsum(term t, term arg, term *next, char *reason)
/* sin(u+v) = sin u cos v + cos u sin v */
{ term u,v;
  unsigned short  n;
  int i;
  if(FUNCTOR(t) != SIN)
     return 1;
  if(FUNCTOR(ARG(0,t)) != '+')
     return 1;
  n = ARITY(ARG(0,t));
  u = ARG(0,ARG(0,t));
  if(n == 2)
     { v = ARG(1,ARG(0,t));
       if(FUNCTOR(v) == '-')
          return 1;  /* use sindif instead */
     }
  else
     { v = make_term('+',(unsigned short)(n-1));
       for(i=0;i<n-1;i++)
          ARGREP(v,i,ARG(i+1,ARG(0,t)));
     }
  *next = sum(product(sin1(u),cos1(v)),product(cos1(u),sin1(v)));
  HIGHLIGHT(*next);
  strcpy(reason,"sin(u+v)=sin u cos v + cos u sin v");
  check_periodic(t);
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sindif(term t, term arg, term *next, char *reason)
/* sin(u-v) = sin u cos v - cos u sin v */
{ term u,v;
  unsigned short  n;
  int i;
  if(FUNCTOR(t) != SIN)
     return 1;
  if(FUNCTOR(ARG(0,t)) != '+')
     return 1;
  n = ARITY(ARG(0,t));
  if(n == 2 && FUNCTOR(ARG(0,ARG(0,t))) == '-')
      { v = ARG(0,ARG(0,ARG(0,t)));
        u = ARG(1,ARG(0,t));
      }
  else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
     return 1;
  else if(n == 2)
     { u = ARG(0,ARG(0,t));
       v = ARG(0,ARG(1,ARG(0,t)));
     }
  else if(n > 2)  /* works only if last arg has a minus sign */
      { if(FUNCTOR(ARG(n-1,ARG(0,t))) != '-')
           return 1;
        v = ARG(0,ARG(n-1,ARG(0,t)));
        u = make_term('+',(unsigned short)(n-1));
        for(i=0;i<n-1;i++)
           ARGREP(u,i,ARG(i,ARG(0,t)));
      }
  *next = sum(product(sin1(u),cos1(v)),tnegate(product(cos1(u),sin1(v))));
  HIGHLIGHT(*next);
  strcpy(reason,"sin(u-v)=sin u cos v - cos u sin v");
  check_periodic(t);
  check_complementary(t);
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cossum(term t, term arg, term *next, char *reason)
/* cos(u+v) = cos u cos v - sin u sin v */
{ term u,v;
  unsigned short  n;
  int i;
  if(FUNCTOR(t) != COS)
     return 1;
  if(FUNCTOR(ARG(0,t)) != '+')
     return 1;
  u = ARG(0,ARG(0,t));
  n = ARITY(ARG(0,t));
  if(n == 2)
     { v = ARG(1,ARG(0,t));
       if(FUNCTOR(v) == '-')
          return 1;  /* use cosdif instead */
     }
  else
     { v = make_term('+',(unsigned short)(n-1));
       for(i=0;i<n-1;i++)
          ARGREP(v,i,ARG(i+1,ARG(0,t)));
     }
  *next = sum(product(cos1(u),cos1(v)),tnegate(product(sin1(u),sin1(v))));
  HIGHLIGHT(*next);
  strcpy(reason,"cos(u+v)=cos u cos v - sin u sin v");
  check_periodic(t);
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cosdif(term t, term arg, term *next, char *reason)
/* cos(u-v)= cos u cos v + sin u sin v */
{ term u,v;
  unsigned short  n;
  int i;
  if(FUNCTOR(t) != COS)
     return 1;
  if(FUNCTOR(ARG(0,t)) != '+')
     return 1;
  n = ARITY(ARG(0,t));
  if(n == 2 && FUNCTOR(ARG(0,ARG(0,t))) == '-')
      { v = ARG(0,ARG(0,ARG(0,t)));
        u = ARG(1,ARG(0,t));
      }
  else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
     return 1;
  else if(n==2)
     { u = ARG(0,ARG(0,t));
       v = ARG(0,ARG(1,ARG(0,t)));
     }
  else if(n > 2)  /* works only if last arg has a minus sign */
      { if(FUNCTOR(ARG(n-1,ARG(0,t))) != '-')
           return 1;
        v = ARG(0,ARG(n-1,ARG(0,t)));
        u = make_term('+',(unsigned short)(n-1));
        for(i=0;i<n-1;i++)
           ARGREP(u,i,ARG(i,ARG(0,t)));
      }
  *next = sum(product(cos1(u),cos1(v)),product(sin1(u),sin1(v)));
  HIGHLIGHT(*next);
  strcpy(reason,"cos(u-v)=cos u cos v + sin u sin v");
  check_periodic(t);
  check_complementary(t);
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tansum(term t, term arg, term *next, char *reason)
/* tan(u+v) = (tan u + tan v)/ (1-tan u tan v) */
{ term u,v,tanu,tanv,s;
  unsigned short  n;
  int i,err;
  if(FUNCTOR(t) != TAN)
     return 1;
  s = ARG(0,t);   /* t = tan s */
  if(FUNCTOR(s) != '+')
     return 1;
  n = ARITY(s);
  u = ARG(0,s);
  if(n == 2)
     { v = ARG(1,s);
       if(FUNCTOR(v) == '-')
          { if(get_mathmode() == AUTOMODE)
               return 1;   /* use tandif instead */
            if(status(tansum) <= LEARNING)
               { errbuf(0, english(1125));
                  /* Use the formula for tan(u-v) instead. */
                 return 1;
               }
          }
     }
  else
     { v = make_term('+',(unsigned short)(n-1));
       for(i=0;i<n-1;i++)
          ARGREP(v,i,ARG(i+1,s));
     }
  tanu = tan1(u);
  tanv = tan1(v);
  if(equals(v,piover2) || equals(u,piover2))
    goto fail;
  err = check(domain(tanu));
  if(err)
     goto fail;
  err = check(domain(tanv));
  if(err)
     goto fail;
  *next = make_fraction(sum(tanu,tanv),sum(one,tnegate(product(tanu,tanv))));
  HIGHLIGHT(*next);
  strcpy(reason, "tan(u+v) = ...");
  /* display_reason can now cope with $-$ text to be parsed and displayed */
  check_periodic(t);
  return 0;
  fail:
     errbuf(0,english(1126));
     /* That would result in an undefined value of tan. */
     return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tandif(term t, term arg, term *next, char *reason)
/* tan(u-v) = (tan u - tan v)/ (1+tan u tan v) */
{ term u,v,tanu,tanv,s;
  unsigned short  n;
  int i,err;
  if(FUNCTOR(t) != TAN)
     return 1;
  s = ARG(0,t);  /* t = tan s */
  if(FUNCTOR(s) != '+')
     return 1;
  n = ARITY(s);
  if(n == 2 && FUNCTOR(ARG(0,s)) == '-')
     { v = ARG(0,ARG(0,s));
       u = ARG(1,s);
     }
  else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
     return 1;
  else if(n == 2)
     { u = ARG(0,s);
       v = ARG(0,ARG(1,s));
     }
  else  /* if(n > 2) */
     { if(FUNCTOR(ARG(n-1,s)) != '-')
          return 1; /* it works only if last arg has a minus sign */
       v = ARG(0,ARG(n-1,s));
       u = make_term('+',(unsigned short)(n-1));
       for(i=0;i<n-1;i++)
          ARGREP(u,i,ARG(i,ARG(0,t)));
     }
  tanu = tan1(u);
  tanv = tan1(v);
  if(equals(v,piover2) || equals(u,piover2))
    goto fail;
  err = check(domain(tanu));
  if(err)
     goto fail;
  err = check(domain(tanv));
  if(err)
     goto fail;
  *next = make_fraction(sum(tanu,tnegate(tanv)),sum(one,product(tanu,tanv)));
  HIGHLIGHT(*next);
  strcpy(reason,"tan(u-v) = ...");
  check_periodic(t);
  return 0;
  fail:
     errbuf(0,english(1126));
     /* That would result in an undefined value of tan. */
     return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cotsum(term t, term arg, term *next, char *reason)
/* cot(u+v)=(cot u cot v-1)/(cot u+cot v) */
/* The right side can be undefined when the left is not,
   for instance cot(u+�) always gives an undefined right side.  */

{ term u,v,cotu,cotv,s,num,denom,w,cancelled;
  unsigned short  n;
  int i,err;
  if(FUNCTOR(t) != COT)
     return 1;
  s = ARG(0,t);   /* t = cot s */
  if(FUNCTOR(s) != '+')
     return 1;
  n = ARITY(s);
  u = ARG(0,s);
  if(equals(u,pi))
     { errbuf(0, english(1124));  /* cot pi is undefined */
       return 1;
     }
  if(FUNCTOR(u) == '*' && !cancel(u,pi,&cancelled,&w) && isinteger(u))
     { errbuf(0, english(1655));
       /* cot m pi is undefined */
       return 1;
     }
  if(n == 2)
     { v = ARG(1,s);
       if(equals(v,pi))
          { errbuf(0, english(1655));
            return 1;
          }
       if(FUNCTOR(v) == '*' && !cancel(v,pi,&cancelled,&w) && isinteger(w))
          { errbuf(0, english(1655));
            /* cot m pi is undefined */
            return 1;
          }
       if(FUNCTOR(v) == '-')
          return 1;  /* use cotdif instead */
     }
  else
     { v = make_term('+',(unsigned short)(n-1));
       for(i=0;i<n-1;i++)
          ARGREP(v,i,ARG(i+1,s));
      }
  cotu = cot1(u);
  cotv = cot1(v);
  if(equals(v,pi) || equals(u,pi))
    goto fail;
  err = check(domain(cotu));
  if(err)
     goto fail;
  err = check(domain(cotv));
  if(err)
     goto fail;
  num = sum(product(cotu,cotv),minusone);
  denom = sum(cotu,cotv);
  *next = make_fraction(num,denom);
  HIGHLIGHT(*next);
  strcpy(reason,"cot(u+v) = ...");
  check_periodic(t);
  return 0;
  fail:
     errbuf(0,english(1127));
     /* That would result in an undefined value of cot. */
     return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cotdif(term t, term arg, term *next, char *reason)
/* cot(u-v)=(1+cot u cot v)/(cot v-cot u) */
{ term u,v,cotu,cotv,s,num,denom;
  unsigned short  n;
  int i,err;
  if(FUNCTOR(t) != COT)
     return 1;
  s = ARG(0,t);  /* t = cot s */
  if(FUNCTOR(s) != '+')
     return 1;
  n = ARITY(s);
  if(n == 2 && FUNCTOR(ARG(0,s)) == '-')
     { v = ARG(0,ARG(0,s));
       u = ARG(1,s);
     }
  else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
     return 1;
  else if(n == 2)
     { u = ARG(0,s);
       v = ARG(0,ARG(1,s));
     }
  else  /* if(n > 2) */
     { if(FUNCTOR(ARG(n-1,s)) != '-')
          return 1; /* it works only if last arg has a minus sign */
       v = ARG(0,ARG(n-1,s));
       u = make_term('+',(unsigned short)(n-1));
       for(i=0;i<n-1;i++)
          ARGREP(u,i,ARG(i,ARG(0,t)));
     }
  cotu = cot1(u);
  cotv = cot1(v);
  if(equals(v,pi) || equals(u,pi))
    goto fail;
  err = check(domain(cotu));
  if(err)
     goto fail;
  err = check(domain(cotv));
  if(err)
     goto fail;
  num = sum(one, product(cotu,cotv));
  denom = sum(cotv, tnegate(cotu));
  *next = make_fraction(num,denom);
  HIGHLIGHT(*next);
  strcpy(reason,"cot(u-v) = ...");
  check_periodic(t);
  return 0;
  fail:
     errbuf(0,english(1127));
     /* That would result in an undefined value of cot. */
     return 1;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublecos1(term t, term arg, term *next, char *reason)
/* cos^2 a - sin^2 a = cos 2a */
{ term lhs,rhs,a;
  int err;
  lhs = sum(make_power(cos1(var0),two),tnegate(make_power(sin1(var0),two)));
  rhs = cos1(product(two,var0));
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       destroy_term(rhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$cos^2 a-sin^2 a=cos 2a$");
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublecos2(term t, term arg, term *next, char *reason)
/* 1 - 2 sin^2 � = cos(2�)                 */
{ term lhs,rhs,a;
  int err;
  lhs = sum(one,tnegate(product(two,make_power(sin1(var0),two))));
  rhs = cos1(product(two,var0));
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       destroy_term(rhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$1 - 2 sin^2 � = cos 2�$");
  return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublecos3(term t, term arg, term *next, char *reason)
/* 2 cos^2 � - 1 = cos(2�)                 */
{ term lhs,rhs,a;
  int err;
  lhs = sum(product(two,make_power(cos1(var0),two)),minusone);
  rhs = cos1(product(two,var0));
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       destroy_term(rhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$2 cos^2 � - 1 = cos 2�$");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int sinoddpower(term t, term arg, term *next, char *reason)
/* sin^(2n+1) u = sin u (1-cos^2 u)^n */
{ term u,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != SIN)
     return 1;
  polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
  if(!isinteger(n))
     return 1;
  u = ARG(0,ARG(0,t));
  *next = product(sin1(u), make_power(sum(one, tnegate(make_power(cos1(u),two))),n));
  HIGHLIGHT(*next);
  strcpy(reason,"sin^(2n+1) u =        sin u (1-cos^2 u)^n");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int cosoddpower(term t, term arg, term *next, char *reason)
/* cos^(2n+1) u = cos u (1-sin^2 u)^n */
{ term u,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != COS)
     return 1;
  polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
  if(!isinteger(n))
     return 1;
  u = ARG(0,ARG(0,t));
  *next = product(cos1(u), make_power(sum(one, tnegate(make_power(sin1(u),two))),n));
  HIGHLIGHT(*next);
  strcpy(reason,"cos^(2n+1) u =        cos u (1-sin^2 u)^n");
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int tanoddpower(term t, term arg, term *next, char *reason)
/* tan^(2n+1) u = tan u (sec^2 u-1)^n */
{ term u,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != TAN)
     return 1;
  polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
  if(!isinteger(n))
     return 1;
  u = ARG(0,ARG(0,t));
  *next = product(tan1(u), make_power(sum(make_power(sec1(u),two),minusone),n));
  HIGHLIGHT(*next);
  strcpy(reason,"tan^(2n+1) u =        tan u (sec^2 u - 1)^n");
  return 0;
}

/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int secoddpower(term t, term arg, term *next, char *reason)
/* sec^(2n+1) u = sec u (tan^2 u+1)^n */
{ term u,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != SEC)
     return 1;
  polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
  if(!isinteger(n))
     return 1;
  u = ARG(0,ARG(0,t));
  *next = product(sec1(u), make_power(sum(make_power(tan1(u),two),one),n));
  HIGHLIGHT(*next);
  strcpy(reason,"sec^(2n+1) u =        sec u (tan^2 u + 1)^n");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int cscoddpower(term t, term arg, term *next, char *reason)
/* csc^(2n+1) u = csc u (cot^2 u+1)^n */
{ term u,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != SEC)
     return 1;
  polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
  if(!isinteger(n))
     return 1;
  u = ARG(0,ARG(0,t));
  *next = product(csc1(u), make_power(sum(make_power(cot1(u),two),one),n));
  HIGHLIGHT(*next);
  strcpy(reason,"csc^(2n+1) u =        csc u (cot^2 u + 1)^n");
  return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int cotoddpower(term t, term arg, term *next, char *reason)
/* cot^(2n+1) u = cot u (csc^2 u-1)^n */
{ term u,n;
  if(FUNCTOR(t) != '^')
     return 1;
  if(FUNCTOR(ARG(0,t)) != SEC)
     return 1;
  polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
  if(!isinteger(n))
     return 1;
  u = ARG(0,ARG(0,t));
  *next = product(cot1(u), make_power(sum(make_power(csc1(u),two),minusone),n));
  HIGHLIGHT(*next);
  strcpy(reason,"cot^(2n+1) u =        cot u (csc^2 u - 1)^n");
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversesinsq(term t, term arg, term *next, char *reason)
/* 1-cos � = 2 sin^2(�/2)  */
{ term lhs,rhs,a;
  int err;
  lhs = sum(one, tnegate(cos1(var0)));
  rhs = product(two, make_power(sin1(make_fraction(var0,two)),two));
  err = match(t,lhs,rhs,&a,next);   /* instantiate a and *next */
  if(err)
     { destroy_term(lhs);
       return 1;
     }
  HIGHLIGHT(*next);
  strcpy(reason,"$1-cos u = 2 sin^2(u/2)$");
  return 0;
}
 /*___________________________________________________________________*/
static void check_periodic(term t)
/* called to generate a comment when a periodicity law is
given a longer proof using trig addition formulae. */
{ unsigned short f;
  term u,v,p,q,temp;
  char buffer[DIMREASONBUFFER];
  int err;
  if(get_mathmode() != AUTOMODE)
     return;  /* only do this in automode */
  if(get_currenttopic() != _trig_addition)
     return;  /* and only under this one topic */
  f = FUNCTOR(t);
  if(!TRIGFUNCTOR(f))
     return;
  u = ARG(0,t);
  if(FUNCTOR(u) != '+' || ARITY(u) != 2)
     return;
  v = ARG(1,u);
  if(NEGATIVE(v))
     v = ARG(0,v);
  if(equals(v,pi))
     err = 0;
  else if(FUNCTOR(v) == '*')
     err = cancel(v,pi,&p,&q);
  else
     err = 1;
  if(err)
     return;
  switch(f)
     { case SIN:
          err = sinperiodic(t,zero,&temp,buffer);
          break;
       case COS:
          err = cosperiodic(t,zero,&temp,buffer);
          break;
       case TAN:
          err = tanperiodic(t,zero,&temp,buffer);
          break;
       case SEC:
          err = secperiodic(t,zero,&temp,buffer);
          break;
       case CSC:
          err = cscperiodic(t,zero,&temp,buffer);
          break;
       case COT:
          err = cotperiodic(t,zero,&temp,buffer);
          break;
     }
  if(err)
     return;
  commentbuf(0, english(1871));
  commentbuf(1, english(1872));
  /* Because the topic is Trig Addition, a solution using
     a trig addition formula will be given, instead of
     a shorter solution using periodicity. */
}

/*___________________________________________________________________*/
static void check_complementary(term t)
/* called to generate a comment when a complentarity law is
given a longer proof using trig addition formulae. */
{ unsigned short f;
  term u,temp;
  char buffer[DIMREASONBUFFER];
  int err;
  if(get_mathmode() != AUTOMODE)
     return;  /* only do this in automode */
  if(get_currenttopic() != _trig_addition)
     return;  /* and only under this one topic */
  f = FUNCTOR(t);
  if(!TRIGFUNCTOR(f))
     return;
  u = ARG(0,t);
  if(FUNCTOR(u) != '+' || ARITY(u) != 2)
     return;
  if(!NEGATIVE(ARG(1,u)))
     return;
  if(!equals(ARG(0,u),piover2))
     return;
  switch(f)
     { case SIN:
          err = sintocos(t,zero,&temp,buffer);
          break;
       case COS:
          err = costosin(t,zero,&temp,buffer);
          break;
     }
  if(err)
     return;
  commentbuf(0, english(1871));
  commentbuf(1, english(1872));
  commentbuf(2, english(1873));
  /* Because the topic is Trig Addition, a proof using
     a trig addition formula will be given, instead of a one-step
     solution by quoting the law stated here as the problem. */
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int makesinpower(term t, term arg, term *next, char *reason)
/* (1-cos x)^n(1+cos x)^n = sin^2n x */
/* But it also works on things like (1-cos x)^2(1+cos x)^3,
leaving a factor of (1+cos x) left over.
   We don't use 'match' since it won't check two levels of
re-ordering.
*/
{ term a,b,c,u,v,w,w2,x,power,power2,extra;
  int i,j,count;
  unsigned short n;
  if(FUNCTOR(t) != '*')
     return 1;
  n = ARITY(t);
  count = 0;
  /* quickly count the powers of sums in t, and fail if there are not 2 */
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == '+')
          ++count;
     }
  if(count < 2)
     return 1;
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) != '^' ||
          FUNCTOR(ARG(0,u)) != '+' ||
          ARITY(ARG(0,u)) != 2 ||
          !isinteger(ARG(1,u))
         )
          continue;
       power = ARG(1,u);
       w = ARG(0,u);
       if(ONE(ARG(0,w)) && FUNCTOR(ARG(1,w)) == COS)
          x = ARG(0,ARG(1,w));
       else if(ONE(ARG(1,w)) && FUNCTOR(ARG(0,w)) == COS)
          x = ARG(0,ARG(0,w));
       else
          continue;
       for(j=0;j<n;j++)
          { if(j==i)
               continue;
            v = ARG(j,t);
            if(FUNCTOR(v) == '^' &&
               FUNCTOR(ARG(0,v)) == '+' &&
               ARITY(ARG(0,v)) == 2 &&
               isinteger(ARG(1,v))
              )
               { w2 = ARG(0,v);
                 power2 = ARG(1,v);
                 if(ONE(ARG(0,w2)) && NEGATIVE(ARG(1,w2)) &&
                    FUNCTOR(ARG(0,ARG(1,w2))) == COS &&
                    equals(ARG(0,ARG(0,ARG(1,w2))),x)
                   )
                     goto out;

               }
          }
     }
  return 1;
  out:
  if(equals(power,power2))
     { polyval(product(two,power),&a);
       *next = make_power(sin1(x),a);
       HIGHLIGHT(*next);
       strcpy(reason,"$(1-cos t)�(1+cos t)� = sin^(2n) t$");
       return 0;
     }
  if(ISINTEGER(power) && ISINTEGER(power2))
     { if (INTDATA(power) < INTDATA(power2))
          { a = make_int(INTDATA(power));
            b = make_int(INTDATA(power2)-INTDATA(power));
            extra = make_power(w2,b);
          }
       else
          { a = make_int(INTDATA(power2));
            b = make_int(INTDATA(power)-INTDATA(power2));
            extra = make_power(w,b);
          }
     }
  else
     { polyval(sum(power,tnegate(power2)),&b);
       if(obviously_positive(b))
           { a = power2;
             extra = make_power(w,b);
           }
       else if(obviously_positive(strongnegate(b)))
           { b = strongnegate(b);
             a = power;
             extra = make_power(w2,b);
           }
     }
  polyval(product(two,a),&c);
  *next = product(make_power(sin1(x),c),extra);
  HIGHLIGHT(*next);
  strcpy(reason,"$(1-cos t)�(1+cos t)� = sin^(2n) t$");
  return 0;
}

/*________________________________________________________________*/
MEXPORT_ALGEBRA int makecospower(term t, term arg, term *next, char *reason)
/* (1-sin x)^n(1+sin x)^n = cos^2n x */
/* But it also works on things like (1-sin x)^2(1+sin x)^3,
leaving a factor of (1+sin x) left over.
*/
{ term a,b,c,u,v,w,w2,x,power,power2,extra;
  int i,j,count;
  unsigned short n;
  if(FUNCTOR(t) != '*')
     return 1;
  n = ARITY(t);
  count = 0;
  /* quickly count the powers of sums in t, and fail if there are not 2 */
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == '+')
          ++count;
     }
  if(count < 2)
     return 1;
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) != '^' ||
          FUNCTOR(ARG(0,u)) != '+' ||
          ARITY(ARG(0,u)) != 2 ||
          !isinteger(ARG(1,u))
         )
          continue;
       power = ARG(1,u);
       w = ARG(0,u);
       if(ONE(ARG(0,w)) && FUNCTOR(ARG(1,w)) == SIN)
          x = ARG(0,ARG(1,w));
       else if(ONE(ARG(1,w)) && FUNCTOR(ARG(0,w)) == SIN)
          x = ARG(0,ARG(0,w));
       else
          continue;
       for(j=0;j<n;j++)
          { if(j==i)
               continue;
            v = ARG(j,t);
            if(FUNCTOR(v) == '^' &&
               FUNCTOR(ARG(0,v)) == '+' &&
               ARITY(ARG(0,v)) == 2 &&
               isinteger(ARG(1,v))
              )
               { w2 = ARG(0,v);
                 power2 = ARG(1,v);
                 if(ONE(ARG(0,w2)) && NEGATIVE(ARG(1,w2)) &&
                    FUNCTOR(ARG(0,ARG(1,w2))) == SIN &&
                    equals(ARG(0,ARG(0,ARG(1,w2))),x)
                   )
                     goto out;

               }
          }
     }
  return 1;
  out:
  if(equals(power,power2))
     { polyval(product(two,power),&a);
       *next = make_power(cos1(x),a);
       HIGHLIGHT(*next);
       strcpy(reason,"$(1-sin t)�(1+sin t)� = cos^(2n) t$");
       return 0;
     }
  if(ISINTEGER(power) && ISINTEGER(power2))
     { if (INTDATA(power) < INTDATA(power2))
          { a = make_int(INTDATA(power));
            b = make_int(INTDATA(power2)-INTDATA(power));
            extra = make_power(w2,b);
          }
       else
          { a = make_int(INTDATA(power2));
            b = make_int(INTDATA(power)-INTDATA(power2));
            extra = make_power(w,b);
          }
     }
  else
     { polyval(sum(power,tnegate(power2)),&b);
       if(obviously_positive(b))
           { a = power2;
             extra = make_power(w,b);
           }
       else if(obviously_positive(strongnegate(b)))
           { b = strongnegate(b);
             a = power;
             extra = make_power(w2,b);
           }
     }
  polyval(product(two,a),&c);
  *next = product(make_power(cos1(x),c),extra);
  HIGHLIGHT(*next);
  strcpy(reason,"$(1-sin t)�(1+sin t)� = cos^(2n) t$");
  return 0;
}

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