Sindbad~EG File Manager
/*
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