Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/automode/
Upload File :
Current File : /usr/home/beeson/MathXpert/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))
5.6.13  include stdef.h
        corrected typo at line 498 that might have resulted in tandif not being used
5.31.13 modified conditions for tanrule, checking bit 5 of trigexpandflag
6.3.13  modified those conditions again, checking bit 0 of trigexpandflag as well, so tanrule will be used if the two functions 
       present have different arguments.
6.4.13  modified conditions for isinh
3.19.23  added some parens to fix scope of !
         added else return 0 near the end of stop_trigexpand
12.7.24 put in calls to get_complex() near contains_complex_var
12.13.24  took those get_complex()  out, so complexcos and complexsin won't be used on real args
1.26.25  added cottocscssec  and modified conditions for cscrule to check bit 4 of trigexpandflag
1.30.25  added dated line to use tanrule as a last resort
1.30.25  added dated line to get cscrule used on csc(pi-x) = csc(x)
1.31.25  changed a bracket in conditions for sinhalf
1.31.25  made stop_trigexpand return 1 if the topic is _fundamental_theorem.
         and made autotrig not use doublecos on _fundamental_theorem.
*/

#include <assert.h>
#define sincos _foo
#include <math.h>    /* fabs, used in ISZERO */
#undef sincos
#include <stddef.h> 
#include <string.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "mpdoc.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;
}
/*_______________________________________________________________*/
static int stop_tanhalf(term t)
/* return 1 if there are other trig functions in the current line than TAN
with a fractional argument in history(currentline)
*/
{
  unsigned f = FUNCTOR(t);
  if(ATOMIC(t))
     return 0;
  if(TRIGFUNCTOR(f) && f != TAN && FUNCTOR(ARG(0,t)) == '/')
     return 1;
  if(TRIGFUNCTOR(f))
     return 0;
  int i;
  unsigned n = ARITY(t);
  for(i=0;i<n;i++)
     { if(stop_tanhalf(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*_______________________________________________________________*/
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;
  const int trigexpandflag = get_trigexpandflag();
  term u;
  unsigned short g,h;
  const int topic = get_currenttopic();
  const int problemtype = get_problemtype();
  const int intflag = get_intflag();
  const int limitflag = get_limitflag();
  const int difflag = get_difflag();
  const int limfractflag = get_limfractflag();
  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 pi) = sin x proved by sum identities under
            topic _trig_addition, not just assumed; but we
            need to use sin(2 pi) = 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_term) )
          { 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 pi), observe x+k pi 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( // 1.30.25
              problemtype == TRIG_IDENTITY &&
              (trigexpandflag & (1 << 3)) &&  // only two trig functions occur
              (trigexpandflag & (1 << 5)) && // all trig functions to the same power
              !(trigexpandflag & 1) &&        // all have the same arg
              !(trigexpandflag & (1 << 4))   // the other function is not TAN or COT
            )
             {  // Example:  (sec(u))^2+(csc(u))^2 = (sec(u))^2 (csc(u))^2
               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^n  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(g == '+' && (trigexpandflag & 1))  // bit 0 means not all trig function have same arg
             { o[i] = cscrule; ++i;
               // 1.30.25, example csc(pi-x) = csc(x)
             }
          if(ARCTRIGFUNCTOR(g) || iscomplex(u))
             { o[i] = cscrule; ++i;
             }
          if( (!(trigexpandflag & (1 << 2)) || (trigexpandflag & 0x01)) &&
               !(trigexpandflag & (1 << 4)) && // bit 4 means only CSC and SEC and COT occur
                                            // so don't introduce sin and cos
              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) || get_complex())
             { 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
                       1  = 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^n  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 & (1 << 4)) &&  /* only cot and tan and csc*/
             !difflag &&   /* don't get rid of cot when differentiating */
             g != '+' &&     /* don't preempt cotsum */
             get_whichpass() > 3   /* this is a last resort */
            )
             { o[i] = cottocscsec; ++i;  //  don't introduce tan, sin, cos
               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 != '+' &&
             !(trigexpandflag & (1 << 4)) &&
             (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;
                          }
                       if(! (trigexpandflag & (1 << 4)))
                          {  // bit 4 set means only CSC, SEC, and COT occur, so
                             // don't introduce SIN and COS
                            o[i] = cottosincos; ++i;
                          }
                     }
                  else if(
                          (trigexpandflag & 0x0004) &&
                          !difflag &&
                          !(trigexpandflag & (1 << 4))
                         )
                     { 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 \theta) 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) || get_complex())
             { 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 == '/' && !stop_tanhalf(history(get_currentline())) &&
             (
               (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 */
             !(FRACTION(ARG(0,t)) && stop_tanhalf(history(get_currentline()))) &&
             ( problemtype != POWERSERIES || intflag || !( (trigexpandflag & (1 << 5)) && !(trigexpandflag & 1))) &&
             /* don't use it outside an integral if there are only two trig functions present, tan and one other, unless they have 
                different arguments (which will show up in a nonzero bit 0 of trigexpandflag)   */
             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 (problemtype == TRIG_IDENTITY && get_whichpass() > 3)
             { o[i] = tanrule; ++i;  // last resort  1.30.25
               // Example:  (1+(tan(x))^2)/(tan(x))^2 = (csc(x))^2
             }
          else if(limitflag && get_whichpass() > 0)
             { o[i] = tanrule; ++i;
             }
          else if(iscomplex(u))
             { o[i] = tanrule; ++i;
             }
          else if((trigexpandflag & 0x01) &&
                   ! limitflag && g != '+' &&
                   ! (FRACTION(ARG(0,t)) && stop_tanhalf(history(get_currentline())))
                 )
             /* 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 != _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 \theta) 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))
             { if(! (pathlength >= 3 && path[0] == '^'))  // don't use on sin(it)^{-1}
                  { 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(pi/2-theta) = cos theta */
                  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 \theta) 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_term) && 
                     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_term) for example */
                     }
                  else if(ARITY(u) == 2 && equals(ARG(1,u),pi_term) && 
                          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_term) */
                     }
                  
                  break;
               case '/':
                  if(ISINTEGER(ARG(0,u)) && ISEVEN(ARG(1,u)))
                     { if((trigexpandflag & 1) || contains_arctrigs(u))
                          { o[i] = sinhalf1; ++i;
                            o[i] = sinhalf2; ++i;
                          }
                     }
                  // need to evaluate sin (pi/8)
                  if(equals(ARG(0,u),pi_term) && ISINTEGER(ARG(1,u)) &&
                          (ispoweroftwo(ARG(1,u)) ||
                           INTDATA(ARG(1,u)) == 12
                          )
                     )
                     { o[i] = sinhalf1; ++i;
                       o[i] = sinhalf2; ++i;
                       /* get e.g. sin(pi/8) and sin(pi/12) evaluated */
                     }
                  //  need to evaluate sin(5 pi/8)
                  if(ISINTEGER(ARG(1,u))  &&
                     (ispoweroftwo(ARG(1,u)) || INTDATA(ARG(1,u)) == 12 )
                     )
                     { // check if numerator is an integer times pi
                       term num = ARG(0,u);
                       if(FUNCTOR(num) == '*' &&
                          ARITY(num) == 2 &&
                          INTEGERP(ARG(0,num)) &&
                          equals(ARG(1,num),pi_term)
                         )
                         { o[i] = sinhalf1; ++i;
                           o[i] = sinhalf2; ++i;
                          /* get e.g. sin(5 pi/8) and sin(5 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(pi/2-theta) = sin theta */
                  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 &&
                     topic != _fundamental_theorem &&
                     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 \theta) 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_term) && 
                     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_term) for example */
                     }
                  else if(ARITY(u) == 2 && equals(ARG(1,u),pi_term) && 
                          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_term) */
                     }
                  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_term) && ISINTEGER(ARG(0,u)) &&
                          (ispoweroftwo(ARG(1,u)) ||
                           INTDATA(ARG(1,u)) == 12
                          )
                         )
                          { o[i] = coshalf1; ++i;
                            o[i] = coshalf2; ++i;
                            /* get e.g. cos(pi/8) and cos(pi/12) evaluated */
                          }
                     }
      
                  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_term) && ISINTEGER(ARG(1,u)) &&
                          (ispoweroftwo(ARG(1,u)) ||
                           INTDATA(ARG(1,u)) == 12
                          )
                     )
                     { o[i] = coshalf1; ++i;
                       o[i] = coshalf2; ++i;
                       /* get e.g. cos(pi/8) and cos(pi/12) evaluated */
                     }
                  //  need to evaluate cos(5 pi/8)
                  if(ISINTEGER(ARG(1,u))  &&
                     (ispoweroftwo(ARG(1,u)) || INTDATA(ARG(1,u)) == 12 )
                     )
                     { // check if numerator is an integer times pi
                       term num = ARG(0,u);
                       if(FUNCTOR(num) == '*' &&
                          ARITY(num) == 2 &&
                          INTEGERP(ARG(0,num)) &&
                          equals(ARG(1,num),pi_term)
                         )
                         { o[i] = coshalf1; ++i;
                           o[i] = coshalf2; ++i;
                          /* get e.g. cos(5 pi/8) and cos(5 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;
}
/*___________________________________________________________________________*/
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.)
   Also we return 1 if the topic is fundamental_theorem,  because
otherwise there is a crash due to repeated use of doublesin.
*/
{ term u = history(get_activeline());
  int topic = get_currenttopic();
  if(topic == _fundamental_theorem)
     return 1;
  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;
     }
 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