Sindbad~EG File Manager

Current Path : /usr/home/beeson/Otter-Lambda/yyy/automode/
Upload File :
Current File : /usr/home/beeson/Otter-Lambda/yyy/automode/autotrig.c

/*
M. Beeson;  trig simplification strategies for Mathpert
1.8.91  original date
6.28.99  modified
1.4.00 added itanh and icoth
1.15.00 added conditions to get sinhalf1, coshalf1, triplesin, triplecos, used on 
        appropriate numerical multiples of pi
2.3.00  added conditions to get sinsum, sindif, cossum, cosdif used on complex arguments
11.21.00 modified conditions for sinsum, cossum, tansum to handle e.g. cos(deg(60)-deg(45))
*/

#define AUTOMODE_DLL
#include <assert.h>
#include <math.h>     /* fabs, used in ISZERO */
#include <string.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "document.h"
#include "tdefn.h"
#include "checkarg.h" /* for operator typedef */
#include "ops.h"  /* for prototypes of operators */
#include "operator.h"
#include "trig.h"
#include "calc.h"
#include "probtype.h"  /* set_control_flags needs values of problemtype */
#include "prover.h"
#include "polynoms.h"
#include "exec.h"
#include "algaux.h"
#include "order.h"
#include "automode.h"
#include "symbols.h"
#include "cflags.h"
#include "autosimp.h"
#include "pvalaux.h"   /* content_factor    */
#include "autosum.h"   /* contains_arctrigs */
#include "autotrig.h"
#include "deval.h"

static int stop_trigexpand(void);
static int ispoweroftwo(term t);
/*______________________________________________________________________*/
static int sincosflag;
void set_sincosflag(int n)
{ sincosflag = n;
}
/*_______________________________________________________________*/
void autotrig(term t,actualop *o, int *nops)
/*  post_ops for the case of a term t with a trig or arctrig functor */
{ unsigned short f = FUNCTOR(t);
  unsigned short localtrigflag=0;
  int trigexpandflag = get_trigexpandflag();
  term u;
  unsigned short g,h;
  int topic = get_currenttopic();
  int problemtype = get_problemtype();
  int intflag = get_intflag();
  int i=0;
  unsigned short const *path = get_path();
  int pathlength = get_pathlength();
  u = ARG(0,t);
  g = FUNCTOR(u);
  if(NOTDEFINED(u))
     { switch(f)
          { case ATAN:
               o[i] = ataninfinity; ++i;
               break;
            case ASEC:
               o[i] = asecinfinity; ++i;
               break;
            case ACSC:
               o[i] = acscinfinity; ++i;
               break;
            case ACOT:
               o[i] = acotinfinity; ++i;
               o[i] = acotminusinfinity; ++i;
               break;
            default:
               o[i] = triginfinity; ++i;
               break;
          }
       *nops = i;
       return;
     }
  if(OBJECT(u) && TYPE(u) == DOUBLE)
     { o[i] = devalop; ++i;
       *nops = i;
       return;
     }
  if(TRIGFUNCTOR(f))
     { if(g=='+' &&
          ( topic != _trig_addition || get_currentline() > 0)
         )
         /* we want sin(x+2�) = sin x proved by sum identities under
            topic _trig_addition, not just assumed; but we
            need to use sin(2�) = 0 in the proof. */
          { switch(f)
               { case SIN:
                    o[i] = sinperiodic; ++i;
                    break;
                 case COS:
                    o[i] = cosperiodic; ++i;
                    break;
                 case TAN:
                    o[i] = tanperiodic; ++i;
                    break;
                 case SEC:
                    o[i] = secperiodic; ++i;
                    break;
                 case CSC:
                    o[i] = cscperiodic; ++i;
                    break;
                 case COT:
                    o[i] = cotperiodic; ++i;
                    break;
               }
          }
       if( g == '*' || ZERO(u) || equals(u,pi) )
          { switch(f)
               { case SIN:
                    o[i] = zeroesofsin; ++i;
                    break;
                 case COS:
                    o[i] = onesofcos;   ++i;
                    break;
                 case TAN:
                    o[i] = zeroesoftan; ++i;
                    break;
               }
          }
       if(ISZERO(u) || (FUNCTOR(u) == DEG && ISZERO(ARG(0,u))))
          { switch(f)
               { case SIN:
                    o[i] = sin0; ++i;
                    break;
                 case COS:
                    o[i] = cos0; ++i;
                    break;
                 case TAN:
                    o[i] = tan0; ++i;
                    break;
               }
          }
       if(contains(u,PI_ATOM) || seminumerical(u))
          { o[i] = (g==DEG ? mod360 : mod2pi); ++i;
            /* You need this for sin(x+k�), observe x+k� isn't seminumerical */
          }
       if(seminumerical(u))
          { /* evaluate trig functions */
            switch(f)
               { case SIN:
                    o[i] = zeroesofsin; ++i;
                    break;
                 case COS:
                    o[i] = onesofcos; ++i;
                    break;
                 case TAN:
                    o[i] = zeroesoftan; ++i;
                    break;
               }
            o[i] = sin90; ++i;
            o[i] = sin30; ++i;
            o[i] = sin45; ++i;
            if(g == DEG && ISINTEGER(ARG(0,u)) && (INTDATA(ARG(0,u)) % 15 == 0))
               { o[i] = combine3045; ++i;
               }
          }
     }
  switch(f)
     { case ATAN:
          if(g == '-')
             { o[i] = arctanodd; ++i;
             }
          o[i] = evalarctan; ++i;
          if(g == TAN)
             { o[i] = atantan; ++i;
             }
          break;
       case ACOS:
          if(g == '-')
             { o[i] = arccosodd; ++i;
             }
          o[i] = evalarccos; ++i;
          break;
       case ASIN:
          if(g == '-')
             { o[i] = arcsinodd; ++i;
             }
          o[i] = evalarcsin; ++i;
          break;
       case ACOT:
          if(!intflag)
             { o[i] = evalarccot; ++i;
             }
          break;
       case ACSC:
          if(!intflag)
             { o[i] = evalarccsc; ++i;
             }
          break;
       case ASEC:
          if(!intflag)
             { o[i] = evalarcsec; ++i;
             }
          break;
       case SEC:
          if(g=='-')
             { o[i] = seceven; ++i;
               break;
             }
          if(g=='+')
             { o[i] = seccomplement; ++i;
             }
          if(ARCTRIGFUNCTOR(g) || iscomplex(u))
             { o[i] = secrule; ++i;
             }
          if( (!(trigexpandflag & 0x10) || (trigexpandflag & 0x01)) &&
                       /* don't use secrule if only tan and sec occur (0x10)
                          unless not all args are the same (0x01), in which
                          case go ahead and use it, e.g. when sec 2x
                          and sec x both occur */
              limfractflag != -1 &&  /* in a limit of fractions */
              (pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3]))  &&
              !(pathlength >= 3 && path[pathlength-3] == '^')
                       /* sec� will be handled in autoexp one level up */
                       /* so if you change these conditions change those too */
                       /* see comments near tanrule */
            )
             { o[i] = secrule; ++i;  /* may be inhibited if inside a sum
                                     containing only sec and tan */
             }
          else if(limfractflag == -1  &&  /* in a limit of fractions */
                  pathlength >= 3 &&
                  path[pathlength-3] == '*'
                  /* a factor of a product in a fraction in a limit */
                 )
             { o[i] = secrule; ++i;
             }
          else if(limitflag && get_whichpass() > 0)
             { o[i] = secrule; ++i;
             }
          else if(SOLVETYPE(problemtype) &&
                  (trigexpandflag & 0x02)
                 )
             /* SEC is the ONLY trig function in the problem;
                bit 0x02 set says there's only one trig function,
                and it must be SEC or we wouldn't be here.
                Without this we can't solve x = sec a  */

             { o[i] = secrule; ++i;
             }
          switch(g)
             { case ATAN:
                  o[i] = secatan; ++i;
                  break;
               case ACOS:
                  o[i] = secacos; ++i;
                  break;
               case ASIN:
                  o[i] = secasin; ++i;
                  break;
             }
          break;
       case CSC:
          if(g=='-')
             { o[i] = cscodd; ++i;
               break;
             }
          if(g=='+')
             { o[i] = csccomplement; ++i;
             }
          if(ARCTRIGFUNCTOR(g) || iscomplex(u))
             { o[i] = cscrule; ++i;
             }
          if( (!(trigexpandflag & 0x100) || (trigexpandflag & 0x01)) &&
              limfractflag != -1 &&
              (pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3])) &&
              /* see comments near tanrule */
              !(pathlength >= 3 && path[pathlength-3] == '^')
              /* see comments at the other 'pathlength-3' */

            )
             { o[i] = cscrule; ++i;  /* may be inhibited inside a sum
                                        containing only csc and cot */
             }
          else if(limfractflag == -1  &&  /* in a limit of fractions */
                  pathlength >= 3 &&
                  path[pathlength-2] == '*'
                  /* a factor of a product in a fraction in a limit */
                 )
             { o[i] = cscrule; ++i;
             }
          else if(limitflag && get_whichpass() > 0)
             { o[i] = cscrule; ++i;
             }
          else if( SOLVETYPE(problemtype ) &&
              (trigexpandflag & 0x02)  /* CSC is the ONLY trig function */
            )
             { o[i] = cscrule; ++i;
             }
          break;
       case COT:
          if(pathlength > 1 && path[pathlength-2] == ATAN)
             { /* simplify arctan(cot x) => arctan(tan(pi/2-x)) */
               o[i] = cottotan2; ++i;
             }
          if(g=='-')
             { o[i] = cotodd; ++i;
               break;
             }
          if(iscomplex(u) || contains_complexvar(u))
             { o[i] = icoth; ++i;
               break;
             }
          if(ARCTRIGFUNCTOR(g))
             /* simplify cot(arcsin x) = 1/tan(arcsin x) */
             { o[i] = cottotan; ++i;
             }
          if(g=='+')
             { o[i] = cotcomplement; ++i;
             }
          /* if only COT and TAN occur, rewrite cot as 1/tan */
          /* example:  1 - cot^2 x
                       ����������  = cot^2 x
                       tan^2 x - 1
             which is solved easily using cot => 1/tan but
             leads to loops if everything is rewritten in sin
             and cos.
          */
          if(g == '/' &&
             ((trigexpandflag & 1) || topic == _half_angle)
            )
             { o[i] = cothalf1; ++i;
               o[i] = cothalf2; ++i;  /* used if cothalf1 is inhibited */
             }
          if(pathlength >= 3 && path[pathlength-3] == '^')
             /* this is in the base of an exponent--postpone
                action till postops handles the exponent.
                If path[pathlength-3] is '^' then path[pathlength-2]
                is 1 or 0 according as we are in denom or num,
                that's why we have 3 here.
                cot� will be handled one level up in autoexp,
                so if you change these conditions change those too. */
              break;
          if(iscomplex(u))
             { o[i] = cottosincos; ++i;
             }
          else if((trigexpandflag & 0x0004) &&  /* only cot and tan */
             !difflag &&   /* don't get rid of cot when differentiating */
             g != '+'      /* don't preempt cotsum */
            )
             { o[i] = cottotan; ++i;
               o[i] = cottosincos; ++i;
               /* e.g. on equation cot x = 0, cottotan can't be applied
               because its side condition cot x != 0 can't be inferred. */
               break;
             }
          else if(limfractflag == -1  &&  /* in a limit of fractions */
                  pathlength >= 3 &&
                  path[pathlength-3] == '*'
                  /* a factor of a product in a fraction in a limit */
                 )
             { o[i] = cottotan; ++i;
             }
          else if(limitflag && get_whichpass() > 0)
             { o[i] = cottosincos; ++i;
             }
          else if(SOLVETYPE(problemtype) &&
                  (trigexpandflag & 0x02)
                 )
             { o[i] = cottotan; ++i;
               o[i] = cottosincos; ++i;
               /* e.g. on equation cot x = 0, cottotan can't be applied
               because its side condition cot x != 0 can't be inferred. */
             }
          if(!(trigexpandflag & 0x100) && limfractflag != -1 &&
             !difflag && g != '+' &&
             (pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3]))
             /* see comments near tanrule */
            )
             { o[i] = cottosincos; ++i;
               break;
             }
          switch(g)
             { case '+':
                  if(trigexpandflag & 1)
                     { o[i] = cotcomplement; ++i;
                       if(topic != _trig_product)
                          { o[i] = cotdif; ++i;
                            o[i] = cotsum; ++i;
                          }
                       if((!trigexpandflag & 0x0004) && !difflag)
                          { o[i] = cottotan; ++i;
                          }
                       o[i] = cottosincos; ++i;
                     }
                  else if((trigexpandflag & 0x0004) && !difflag)
                     { o[i] = cottotan; ++i;
                       o[i] = cottosincos; ++i;
                     }
                  set_trigflag(u,&localtrigflag);
                  if(ARCTRIGSPRESENT(localtrigflag))
                     { o[i] = cotdif; ++i;
                       o[i] = cotsum; ++i;
                       o[i] = cottosincos; ++i;
                     }
                  break;
               case '*':
                  if (trigexpandflag & 1)
                     { o[i] = doublecot; ++i;
                     }
                  h = FUNCTOR(ARG(1,u));
                  if(h==ASIN || h==ACOS || h == ATAN || h == ASEC || h == ACSC || h==ACOT)
                      /* we must always expand cot(2 acot �) etc.; these
                         expressions sometimes arise in answers to integrals. */
                     { o[i] = doublecot; ++i;
                       if(RATIONALP(ARG(0,u)) &&
                          ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
                         )
                          { o[i] = cothalf1; ++i;
                            o[i] = cothalf2; ++i;
                          }
                     }
                  break;
             }
          break;
       case TAN:
          if(iscomplex(u) || contains_complexvar(u))
             { o[i] = itanh; ++i;
               break;
             }
          if(pathlength >= 3 && path[pathlength-3] == ACOT)
             { /* simplify arccot(tan x) => arccot(cot(pi/2-x)) */
               o[i] = tantocot2; ++i;
             }
          if(g == '+')
             { o[i] = tantocot; ++i;
             }
          if( g == '/' &&
             (
               (trigexpandflag & 1) ||
               topic == _half_angle ||
               (equals(ARG(1,u),two) && ARCTRIGFUNCTOR(FUNCTOR(ARG(0,u))))
                 /* tan(arcsin(x)/2) will simplify */
             )
            )
             { o[i] = tanhalf1; ++i;
               o[i] = tanhalf2; ++i;  /* used if tanhalf1 is inhibited */
             }

          /* Now for tanrule (tan=>sin/cos).  The conditions
             are somewhat intricate. */

          if(!(trigexpandflag & 0x0010) &&
             /* don't use it if only tan and sec are present */
             !(trigexpandflag & 0x0004) &&
             /* don't use it if only cot and tan are present */
             limfractflag != -1 && /* don't use it in a limit of
             fractions, but it's ok in a fraction of limits */
             !difflag && /* don't use it inside derivatives, e.g.
             d/dx cos(tan x) should not go to d/dx(cos(sin x/cos x))*/
             (pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3]))
             /* don't use it e.g. in cos(tan x) even AFTER
             derivatives are gone  */
            )
             /* tanrule may be inhibited if in a sum containing only tan and sec */
             { o[i] = tanrule; ++i;
               break;
             }
          else if(limitflag && get_whichpass() > 0)
             { o[i] = tanrule; ++i;
             }
          else if(iscomplex(u))
             { o[i] = tanrule; ++i;
             }
          else if((trigexpandflag & 0x01) && ! limitflag && g != '+')
             /* Use it anyway if not all trig functions have the same arg */
             /* but not inside a limit, else we can't solve
                lim(x->0,tan(3x)/tan(2x)) properly; and in case g == '+',
                we don't want to preempt tandif and tansum thrown in below. */
             { if(g == '*')
                  { o[i] = doubletan; ++i;
                  }
               o[i] = tanrule; ++i;
               break;
             }
          switch(g)
             {  case '+':
                  if( 
                      (trigexpandflag & 1) ||
                      /* tan(deg(60) - deg(45)) etc. */
                      (ARITY(u)==2 && seminumerical(u))
                    )
                     { if(topic != topic != _trig_product)
                          { o[i] = tandif; ++i;
                            o[i] = tansum; ++i;
                          }
                       o[i] = tanrule; ++i;
                       /* tansum can fail if one of the new terms is undefined,
                          so throw in tanrule in any case. */
                     }
                  set_trigflag(u,&localtrigflag);
                  if(ARCTRIGSPRESENT(localtrigflag))
                     { o[i] = tandif; ++i;
                       o[i] = tansum; ++i;
                     }
                  break;
               case '*':
                  if(limitflag && (trigexpandflag & 1))
                     /* if !limitflag, it was already thrown in above, so as
                        to preempt tanrule */
                      { o[i] = doubletan; ++i;
                      }
                  h = FUNCTOR(ARG(1,u));
                  if(h==ASIN || h==ACOS || h == ATAN || h == ASEC || h == ACSC || h==ACOT)
                      /* we must always expand tan(2 atan �) etc.; these
                         expressions sometimes arise in answers to integrals. */
                     { o[i] = doubletan; ++i;
                       if(RATIONALP(ARG(0,u)) &&
                          ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
                         )
                          /* e.g., tan((1/4) arctan u) */
                          { o[i] = tanhalf1; ++i;
                            o[i] = tanhalf2; ++i;
                          }
                     }
                  break;
               case ATAN:
                  o[i] = tanatan; ++i;
                  break;
               case ACOS:
                  o[i] = tanacos; ++i;
                  break;
               case ASIN:
                  o[i] = tanasin; ++i;
                  break;
             }
          break;
       case SIN:
          if(pathlength >= 3 && path[pathlength-3] == ACOS)
             { /* simplify arccos(sin x) => arccos(cos(pi/2-x)) */
               o[i] = sintocos2; ++i;
             }
          if(iscomplex(u) || contains_complexvar(u)) 
             { o[i] = isinh; ++i;
               if(FUNCTOR(u) == '+')
                  { o[i] = sindif; ++i;
                    o[i] = sinsum; ++i;
                  }
               else
                  { o[i] = complexsin; ++i;
                  }
               break;
             }
          switch(g)
             { case '+' :
                  o[i] = sintocos; ++i;  /* sin(�/2-�) = cos � */
                  if(
                      ((trigexpandflag & 1) && topic != _trig_product) ||
                       /* sin(deg(60) - sin(45)) etc. */
                      (ARITY(u)==2 && seminumerical(u))
                    )
                     { o[i] = sindif; ++i;
                       o[i] = sinsum; ++i;
                     }
                  else if(seminumerical(ARG(0,t)) && contains(t,DEG))
                      /* example:  sin(60 degrees - 30 degrees), which
                         arises in evaluating sin(15 degrees) */
                     { o[i] = sindif; ++i;
                       o[i] = sinsum; ++i;
                     }
                  else
                     { set_trigflag(u,&localtrigflag);
                       if(ARCTRIGSPRESENT(localtrigflag))
                         { o[i] = sindif; ++i;
                           o[i] = sinsum; ++i;
                         }
                     }
                  break;
               case '*':
                  if((trigexpandflag & 1) &&
                     ! difflag &&
                     (trigexpandflag & (1 << 12)) && /* only SIN and COS occur */
                     topic != _trig_product &&
                     problemtype != LIMITS &&
                     problemtype != LHOPITAL &&
                     (problemtype != INTEGRATION || intflag) &&
                       /* but don't put indexflag in because there's no use
                          expanding trig functions in indexed sums. */
                       /* we sometimes use reversedoublesin in limits,
                          and then we don't want to undo the result;
                          and AFTER doing an integral, we are perfectly
                          content with an answer like sin x + sin 4x,
                          but INSIDE an integral go ahead and
                          expand, e.g. 1/(sin x + sin 2x)
                       */
                     (!SOLVETYPE(problemtype) || !stop_trigexpand())
                     /* Example: -sin x + 2 sin x sin 4x = 0, we must not
                        expand sin 4x before factoring the left side.  The
                        factoring only happens in postops on the sum, so we
                        have to NOT expand sin 4x on pass 0. */
                    )
                     { o[i] = doublesin; ++i;
                       if(!get_infractionflag())
                          { o[i] = triplesin; ++i;
                            o[i] = expandsin; ++i;
                          }
                           /* sumofsin is now in pre_ops so it's
                              safe to use these here even though
                              sin 5x + sin 3x = 0 should not be solved
                              by expanding but by combining.
                            */
                     }
                  h = FUNCTOR(ARG(1,u));
                  if(h==ASIN || h==ACOS || h == ATAN || h == ASEC || h == ACSC || h==ACOT)
                      /* we must always expand sin(2 asin �) etc.; these
                         expressions sometimes arise in answers to integrals. */
                     { o[i] = doublesin; ++i;
                       if(RATIONALP(ARG(0,u)) &&
                          ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
                          /* e.g., sin((1/4) arctan u) */
                         )
                          { o[i] = sinhalf1; ++i;
                            o[i] = sinhalf2; ++i;
                          }
                     }
                  if(ARITY(u) == 2 && equals(ARG(1,u),pi) && 
                     RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),three) &&
                     ispoweroftwo(ARG(1,ARG(0,u)))
                    )
                     { o[i] = triplesin; ++i;  /* evaluate sin((3/8) pi) for example */
                     }
                  else if(ARITY(u) == 2 && equals(ARG(1,u),pi) && 
                          RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),two) &&
                          equals(ARG(1,ARG(0,u)),three)
                          )
                     { o[i] = doublesin; ++i;  /* evaluate sin((2/3) pi) */
                     }
                  
                  break;
               case '/':
                  if(ISINTEGER(ARG(1,u)) && ISEVEN(ARG(1,u)))
                     { if((trigexpandflag & 1) || contains_arctrigs(u))
                          { o[i] = sinhalf1; ++i;
                            o[i] = sinhalf2; ++i;
                          }
                       if(equals(ARG(0,u),pi) && ISINTEGER(ARG(1,u)) &&
                          (ispoweroftwo(ARG(1,u)) || 
                           INTDATA(ARG(1,u)) == 12
                          )
                         )
                          { o[i] = sinhalf1; ++i;
                            /* get e.g. sin(pi/8) and sin(pi/12) evaluated */
                          }
                     }
                  break;
               case ATAN:
                  o[i] = sinatan; ++i;
                  break;
               case ACOS:
                  o[i] = sinacos; ++i;
                  break;
               case ASIN:
                  o[i] = sinasin; ++i;
                  break;
             }
           break;

       case COS:
          if(pathlength >= 3 && path[pathlength-3] == ASIN)
             { /* simplify arcsin(cos x) => arcsin(sin(pi/2-x)) */
               o[i] = costosin2; ++i;
             }
          if(iscomplex(u) || contains_complexvar(u))
             { o[i] = icosh; ++i;
              if(FUNCTOR(u) == '+')
                  { o[i] = cosdif; ++i;
                    o[i] = cossum; ++i;
                  }
               else
                  { o[i] = complexcos; ++i;
                  }
               break;
             }
          switch(g)
             { case '+' :
                  o[i] = costosin; ++i;   /* cos(�/2-�) = sin � */
                  if(
                     ((trigexpandflag & 1) && topic != _trig_product) ||
                     /* cos(deg(60) - deg(45)) etc. */
                     (ARITY(u)==2 && seminumerical(u))
                    )
                     { o[i] = cosdif; ++i;
                       o[i] = cossum; ++i;
                     }
                  set_trigflag(u,&localtrigflag);
                  if(ARCTRIGSPRESENT(localtrigflag))
                     { o[i] = cosdif; ++i;
                       o[i] = cossum; ++i;
                     }
                  break;
               case '*':
                  if((trigexpandflag & 1) &&
                     ! difflag &&
                     (trigexpandflag & (1 << 12)) && /* only SIN and COS occur */
                     topic != _trig_product &&
                     problemtype != LIMITS &&
                     problemtype != LHOPITAL &&
                     (problemtype != INTEGRATION || intflag) &&
                       /* but don't but indexflag in because there's no use
                          expanding trig functions in indexed sums. */
                       /* we sometimes use reversedoublesin in limits,
                          and then we don't want to undo the result;
                          and AFTER doing an integral, we are perfectly
                          content with an answer like sin x + sin 4x,
                          but INSIDE an integral go ahead and
                          expand, e.g. 1/(sin x + sin 2x)
                       */
                     (!SOLVETYPE(problemtype) || !stop_trigexpand())
                     /* Example: -sin x + 2 sin x sin 4x = 0, we must not
                        expand sin 4x before factoring the left side.  The
                        factoring only happens in postops on the sum, so we
                        have to NOT expand sin 4x on pass 0. */

                    )
                     { if(trigexpandflag & 2)  /* only one trig function occurs,
                                                  which perforce is COS */
                          { o[i] = doublecos3; ++i;  /* cos 2t = 2cos^2 t-1 */
                          }
                       else if(FUNCTOR(ARG(1,u)) == ACOS)
                          { o[i] = doublecos3; ++i;  /* cos(2 arccos t) = 2(cos^arccos t)^2 - 1 */
                          }
                       else if(FUNCTOR(ARG(1,u)) == ASIN)
                          { o[i] = doublecos2; ++i;  /* cos(2 arcsin t) = 1- 2sin^2(arcsin t) */
                          }
                       else if(sincosflag == SIN)
                          { o[i] = doublecos2; ++i;
                          }
                       else if(sincosflag == COS)
                          { o[i] = doublecos3; ++i;
                          }
                       else
                          { o[i] = doublecos1; ++i;  /* cos 2t = cos^2 t - sin^2 t */
                          }
                             /*  sumofcos is now in pre_ops, so will not be
                                 pre-empted here.  This is good as an equation
                                 like cos 5x + cos 3x = 0 should not be
                                 solved by expanding but by combining.
                              */
                       if(!get_infractionflag())
                          { o[i] = triplecos; ++i;
                            o[i] = expandcos; ++i;
                          }
                     }
                  h = FUNCTOR(ARG(1,u));
                  if(h == ACOS)
                     { o[i] = doublecos3; ++i;  /* cos(2 arccos t) = 2(cos^arccos t)^2 - 1 */
                       if(RATIONALP(ARG(0,u)) &&
                          ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
                         )
                          /* e.g., cos((1/4) arctan u) */
                          { o[i] = coshalf1; ++i;
                            o[i] = coshalf2; ++i;
                          }
                     }
                  else if(h == ASIN)
                     { o[i] = doublecos2; ++i;  /* cos(2 arcsin t) = 1- 2sin^2(arcsin t) */
                       if(RATIONALP(ARG(0,u)) &&
                          ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
                         )
                          /* e.g., cos((1/4) arctan u) */
                          { o[i] = coshalf1; ++i;
                            o[i] = coshalf2; ++i;
                          }
                     }
                  if(h == ATAN || h == ASEC || h == ACSC || h==ACOT)
                      /* we must always expand cos(2 acos �) etc.; these
                         expressions sometimes arise in answers to integrals. */
                     { o[i] = doublecos1; ++i;
                       if(RATIONALP(ARG(0,u)) &&
                          ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
                         )
                          /* e.g., cos((1/4) arctan u) */
                          { o[i] = coshalf1; ++i;
                            o[i] = coshalf2; ++i;
                          }
                     }
                  if(ARITY(u) == 2 && equals(ARG(1,u),pi) && 
                     RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),three) &&
                     ispoweroftwo(ARG(1,ARG(0,u)))
                     )
                     { o[i] = triplecos; ++i;  /* evaluate cos((3/8) pi) for example */
                     }
                  else if(ARITY(u) == 2 && equals(ARG(1,u),pi) && 
                          RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),two) &&
                          equals(ARG(1,ARG(0,u)),three)
                          )
                     { o[i] = doublecos1; ++i;  /* evaluate cos((2/3) pi) */
                     }
                  break;
               case '/':
                  if(ISINTEGER(ARG(1,u)) && ISEVEN(ARG(1,u)))
                     { if((trigexpandflag & 1) || contains_arctrigs(u))
                          { o[i] = coshalf1; ++i;
                            o[i] = coshalf2; ++i;
                          }
                       if(equals(ARG(0,u),pi) && ISINTEGER(ARG(1,u)) &&
                          (ispoweroftwo(ARG(1,u)) || 
                           INTDATA(ARG(1,u)) == 12
                          )
                         )
                          { o[i] = coshalf1; ++i;
                            /* get e.g. cos(pi/8) and cos(pi/12) evaluated */
                          }
                     }
                  break;
               case ATAN:
                  o[i] = cosatan; ++i;
                  break;
               case ACOS:
                  o[i] = cosacos; ++i;
                  break;
               case ASIN:
                  o[i] = cosasin; ++i;
                  break;
             }
           break;
     }
  *nops = i;
}
/*___________________________________________________________________________*/
MEXPORT_AUTOMODE int contains_complexvar(term t)
/* return 1 if t contains a variable with type DCOMPLEX */
{ unsigned short n;
  int i;
  if(ISATOM(t) && TYPE(t) == DCOMPLEX)
     return 1;
  if(ATOMIC(t))
     return 0;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_complexvar(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*__________________________________________________________________*/
static int stop_trigexpand(void)
/* return 1 if the active line has the form sum = 0 and the
sum will content_factor.  (In that case, we don't want to expand
trig functions like sin 4x, because after the content-factoring,
they may be isolated in an equation containing only trig functions of 4x.)
*/
{ term u = history(get_activeline());
  term t,a,b;
  int k,err;
  unsigned short const *path = get_path();
  int pathlength = get_pathlength();
  if(pathlength == 0)
     return 0;
  if(path[0] == '=')
     { k = path[1] == 2 ? 0 : 1;
       if(ZERO(ARG(k,u)))
          t = ARG(path[1] - 1,u);
       else
          return 0;
     }
  else if(path[0] == OR)
     { u = ARG(path[1] - 1,u);
       if(pathlength < 3)
          return 0;
       k = path[3] == 2 ? 0 : 1;
       if(ZERO(ARG(k,u)))
          t = ARG(path[3] - 1, u);
       else
          return 0;
     }
 err = content_factor(t,&a,&b);
 return err ? 0 : 1;
}

/*______________________________________________________________________________*/
static int ispoweroftwo(term t)
/* return 1 if t is a nonzero integer which is a power of two.
Don't count bignums.  Return 0 otherwise. */
{ long m;
  if(!ISINTEGER(t))
     return 0;
  m = INTDATA(t);
  if(m == 0)
     return 0;
  while(!(m & 1))
     { m = m >> 1;
     }
  m = m >> 1;
  if(m == 0)
     return 1;
  return 0;
}


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