Sindbad~EG File Manager
/*
Trig operators for MathXpert
M. Beeson
Original date 1.13.91
Last modified 3.23.98
2.9.05 modified includes
3.17.06 modified sinsin, sincos, coscos, cossin using u = sum(a[0],a[1]) to make gcc happy.
4.8.07 added cast to (int) at line 1509
5.6.13 made recip_aux2 static
1.25.25 added inhibit(sumofcos); inhibit(sumofsin);
and in those operations, inhibit(sinsin); inhibit(coscos); inhibit(sincosop); inhibit(cossin);
1.26.25 added missing $$ in sintocsc and another place
*/
#include <string.h>
#include <math.h>
#include <assert.h>
#include "globals.h"
#include "ops.h"
#include "trig.h"
#include "match.h"
#include "order.h"
#include "cancel.h"
#include "simpsums.h" /* collect */
#include "checkarg.h" /* needed by automode.h */
#include "graphstr.h"
#include "coord.h"
#include "mpdoc.h"
#include "automode.h" /* get_intflag */
#include "mstring.h" /* mstring */
#include "deval.h"
#include "symbols.h"
#include "pvalaux.h" /* content_factor */
#include "mathmode.h" /* get_mathmode */
#include "calc.h" /* polyvalop */
#include "errbuf.h"
#include "autosimp.h" /* set_pathtail, SetShowStepOperation */
#include "tdefn.h" /* _trig_factor */
#include "probtype.h" /* SOLVETYPE */
#include "periodic.h" /* periodic_in */
#include "eqn.h" /* solved */
#include "prover.h" /* ISINFINITE */
#include "mplimits.h" /* LIMITAND */
static int sumtrig_aux(actualop o, term t, term arg, term *next, char *reason);
static int sqeven(unsigned short f, term t, term *next, char *reason);
static term trigsimp(term t);
static void adjust_polyvalfunctionflag( term t);
static int multipleofpi(term a);
static int odd_multiple_of_piover2(term a);
/*__________________________________________________________________*/
static int apply_aux(actualop o, term t, term arg, term *next, char *reason)
/* t must be a product or an integral. If an integral, and the
integrand is a fraction, apply operator o to the denominator.
If t is a product, apply operator o to one of the factors u of t
and if the result is a fraction p/q, make next a fraction with
denominator q and numerator the result of replacing u by p in t.
Return 0 for success.
*/
{ int i,k,err;
unsigned short n = ARITY(t);
term u,v,p,q,num;
unsigned short path[5];
if(FUNCTOR(t) == INTEGRAL)
{ if(!FRACTION(ARG(0,t)))
return 1;
u = ARG(1,ARG(0,t)); /* the denom of the integrand */
err = (*o)(u,arg,&v,reason);
if(err)
return 1;
if(ONE(ARG(0,ARG(0,t))))
p = reciprocal(v);
else
mfracts(ARG(0,ARG(0,t)),reciprocal(v),&p);
*next = ARITY(t) == 2 ? integral(p,ARG(1,t)) : definite_integral(p,ARG(1,t),ARG(2,t),ARG(3,t));
path[0] = INTEGRAL;
path[1] = 1;
path[2] = '/';
path[3] = 2;
path[4] = 0;
set_pathtail(path);
return 0;
}
assert(FUNCTOR(t) == '*');
for(i=0;i<n;i++)
{ u = ARG(i,t);
err = (* o)(u,arg,&v,reason);
if(!err)
break;
}
if(i==n)
return 1;
path[0] = '*';
path[1] = i+1;
path[2] = 0;
set_pathtail(path);
if(FRACTION(v))
{ p = ARG(0,v);
q = ARG(1,v);
}
else
{ p = v;
q = one;
}
if(ONE(p) && n==2)
{ num = ARG(i ? 0 : 1,t);
*next = make_fraction(num,q);
return 0;
}
if(ONE(p))
{ num = make_term('*',(unsigned short)(n-1));
for(k=0;k<n-1;k++)
ARGREP(num,k,ARG(k<i ? k : k+1, t));
*next = make_fraction(num,q);
return 0;
}
num = make_term('*',n);
for(k=0;k<n;k++)
ARGREP(num,k,k!=i ? ARG(k,t) : p);
*next = make_fraction(num,q);
HIGHLIGHT(*next);
return 0;
}
/*__________________________________________________________________*/
int doublecos5(term t, term arg, term *next, char *reason)
/* cos 2 theta + 1 = 2 cos^2 theta */
{ term lhs,rhs,a;
int err;
if(FUNCTOR(t) != '+')
return 1;
lhs = sum(cos1(product(two,var0)),one);
rhs = product(two,make_power(cos1(var0),two));
err = match(t,lhs,rhs,&a,next); /* instantiate a and *next */
if(err)
{ destroy_term(lhs);
destroy_term(rhs);
return 1;
}
HIGHLIGHT(*next);
strcpy(reason,"$cos 2\\theta + 1 = 2cos^2 \\theta$");
return 0;
}
/*__________________________________________________________________*/
int doublecos6(term t, term arg, term *next, char *reason)
/* cos 2 theta - 1 = - 2 sin^2 theta */
{ term lhs,rhs,a;
int err;
if(FUNCTOR(t) != '+')
return 1;
lhs = sum(cos1(product(two,var0)),minusone);
rhs = tnegate(product(two,make_power(sin1(var0),two)));
err = match(t,lhs,rhs,&a,next); /* instantiate a and *next */
if(err)
{ destroy_term(lhs);
destroy_term(rhs);
return 1;
}
HIGHLIGHT(*next);
strcpy(reason,"$cos 2\\theta - 1 = -2 sin^2 \\theta$");
return 0;
}
/*__________________________________________________________________*/
int doublecos4(term t, term arg, term *next, char *reason)
/* cos 2 theta = cos^2 theta - sin^2 theta (must be tried last in auto mode)*/
/* associated to '+' for use when cos 2 theta is a summand. See doublecos1. */
{ int i,j,err;
unsigned short n;
unsigned short path[5];
term u,v,theta,cancelled;
if(FUNCTOR(t) != '+')
return 1;
n = ARITY(t);
for(i=0;i<n;i++) /* look for cos 2 theta*/
{ u = ARG(i,t);
if(FUNCTOR(u)==COS)
{ v = ARG(0,u);
err = cancel(v,two,&cancelled,&theta);
if(!err)
break;
}
}
if(i==n)
return 1; /* no cos 2 theta found */
*next = make_term('+',(unsigned short)(n+1));
for(j=0;j<n+1;j++)
{ if(j<i)
ARGREP(*next,j,ARG(j,t));
else if(j==i)
ARGREP(*next,j,make_power(cos1(theta),two));
else if(j==i+1)
ARGREP(*next,j,tnegate(make_power(sin1(theta),two)));
else
ARGREP(*next,j,ARG(j-1,t));
}
HIGHLIGHT(*next);
path[0] = '+';
path[1] = i+1;
path[2] = 0;
set_pathtail(path);
SetShowStepOperation(doublecos1);
strcpy(reason,"$cos 2\\theta=cos^2 \\theta -sin^2 \\theta$");
return 0;
}
/*___________________________________________________________*/
int secrule(term t, term arg, term *next, char *reason)
/* sec x = 1 / cos x */
/* also in the denom of an integral */
/* also in a limit at infinity or a singularity */
{ term u;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == SEC)
{ u = cos1(ARG(0,ARG(0,t)));
*next = reciprocal(make_power(u,ARG(1,t)));
goto out;
}
if(f == '*' || (f == INTEGRAL && FRACTION(ARG(0,t))))
return apply_aux(secrule,t,arg,next,reason);
if(f == LIMIT)
{ term a = ARG(1,ARG(0,t));
term u = LIMITAND(t);
term v;
int err;
unsigned short n = ARITY(t);
unsigned short path[5];
/* work if a is an odd multiple of pi/2 or if a is infinite */
if(!ISINFINITE(a) && !odd_multiple_of_piover2(a))
return 1;
if(FUNCTOR(u) != SEC)
return 1;
err = secrule(u,arg,&v,reason);
if(err)
return 1;
if(ARITY(t) == 2)
*next = limit(ARG(0,t),v);
else
*next = limit3(ARG(0,t),ARG(1,t),v);
path[0] = LIMIT;
path[1] = n ==2 ? 2 : 3;
path[2] = 0;
set_pathtail(path);
return 0;
}
if(f != SEC)
return 1;
*next = reciprocal(cos1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$sec x = 1 / (cos x)$$");
return 0;
}
/*___________________________________________________________*/
int costosec(term t, term arg, term *next, char *reason)
/* cos x = 1 / sec x */
{ term u;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == COS)
{ u = sec1(ARG(0,ARG(0,t)));
*next = reciprocal(make_power(u,ARG(1,t)));
goto out;
}
if(f == '*')
return apply_aux(costosec,t,arg,next,reason);
if(f != COS)
return 1;
*next = reciprocal(sec1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$cos x = 1 / (sec x)$$");
return 0;
}
/*___________________________________________________________*/
int sintocsc(term t, term arg, term *next, char *reason)
/* sin x = 1 / csc x */
{ term u;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == SIN)
{ u = csc1(ARG(0,ARG(0,t)));
*next = reciprocal(make_power(u,ARG(1,t)));
goto out;
}
if(f == '*')
return apply_aux(sintocsc,t,arg,next,reason);
if(f != SIN)
return 1;
*next = reciprocal(csc1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$sin x = 1 / (csc x)$$");
return 0;
}
/*___________________________________________________________*/
int tantodenom(term t, term arg, term *next, char *reason)
/* tan x = 1 / cot x */
{ term u,x;
int err;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == TAN)
{ x = ARG(0,ARG(0,t));
err = check1(nonzero(tan1(x)));
if(err)
{ err = check1(nonzero(sin1(x)));
if(err)
{ errbuf(0,english(1833));
/* Cannot verify that tan x is nonzero.", */
if(SOLVETYPE(get_problemtype()))
{ errbuf(1,english(1838));
errbuf(2,english(1839));
/* You might lose solutions by applying that law
without first verifying that condition. */
}
return 1;
}
}
u = cot1(x);
*next = reciprocal(make_power(u,ARG(1,t)));
goto out;
}
if(f == '*')
return apply_aux(tantodenom,t,arg,next,reason);
if(f != TAN)
return 1;
x = ARG(0,t);
err = check1(nonzero(tan1(x)));
if(err)
{ err = check1(nonzero(sin1(x)));
if(err)
{ errbuf(0,english(1833));
/* Cannot verify that tan x is nonzero.", */
if(SOLVETYPE(get_problemtype()))
{ errbuf(1,english(1838));
errbuf(2,english(1839));
/* You might lose solutions by applying that law
without first verifying that condition. */
}
return 1;
}
}
*next = reciprocal(cot1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$tan x = 1 / (cot x)$$");
return 0;
}
/*__________________________________________________________________*/
int cscrule(term t, term arg, term *next, char *reason)
/* csc x = 1 / sin x */
/* also in the denom of an integral */
/* also in a limit at infinity or singularity */
{ term u;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == CSC)
{ u = sin1(ARG(0,ARG(0,t)));
*next = reciprocal(make_power(u,ARG(1,t)));
goto out;
}
if(f == '*' || f == INTEGRAL)
return apply_aux(cscrule,t,arg,next,reason);
if(f == LIMIT)
{ term a = ARG(1,ARG(0,t));
term u = LIMITAND(t);
term v;
int err;
unsigned short path[5];
unsigned short n = ARITY(t);
if(!ISINFINITE(a) && !multipleofpi(a))
return 1;
if(FUNCTOR(u) != CSC)
return 1;
err = cscrule(u,arg,&v,reason);
if(err)
return 1;
if(ARITY(t) == 2)
*next = limit(ARG(0,t),v);
else
*next = limit3(ARG(0,t),ARG(1,t),v);
path[0] = LIMIT;
path[1] = n==2 ? 2 : 3;
path[2] = 0;
set_pathtail(path);
return 0;
}
if(f != CSC)
return 1;
*next = reciprocal(sin1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$csc x = 1 / (sin x)$$");
return 0;
}
/*__________________________________________________________________*/
int cottotan(term t, term arg, term *next, char *reason)
/* cot x = 1/tan x */
/* only valid if tan x != 0 , but we don't need to check that
as it is not a NEW assumption, i.e. cot x is undefined the
same places tan x = 0. On the other hand, the right side
requires cos x != 0 as well, which is not required on the left.
So THIS assumption must be checked.
*/
{ term u,x;
int err;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == COT)
{ x = ARG(0,ARG(0,t));
err = check1(nonzero(cot1(x)));
if(err)
{ err = check1(nonzero(cos1(x)));
if(err)
{ errbuf(0,english(1834));
/* Cannot verify that cot x is nonzero. */
if(SOLVETYPE(get_problemtype()))
{ errbuf(1,english(1838));
errbuf(2,english(1839));
/* You might lose solutions by applying that law
without first verifying that condition. */
}
return 1;
}
}
u = tan1(x);
*next = reciprocal(make_power(u,ARG(1,t)));
goto out;
}
if(f == LIMIT)
{ term a = ARG(1,ARG(0,t));
term u = LIMITAND(t);
term v;
unsigned short path[5];
unsigned short n = ARITY(t);
if(!ISINFINITE(a))
return 1;
if(FUNCTOR(u) != COT)
return 1;
err = cottotan(u,arg,&v,reason);
if(err)
return 1;
if(ARITY(t) == 2)
*next = limit(ARG(0,t),v);
else
*next = limit3(ARG(0,t),ARG(1,t),v);
path[0] = LIMIT;
path[1] = n==2 ? 2 : 3;
path[2] = 0;
set_pathtail(path);
return 0;
}
if(f == '*' || f == INTEGRAL)
return apply_aux(cottotan,t,arg,next,reason);
if(f != COT)
return 1;
x = ARG(0,t);
err = check1(nonzero(cot1(x)));
if(err)
{ err = check1(nonzero(cos1(x)));
if(err)
{ errbuf(0,english(1834));
/* Cannot verify that cot x is nonzero. */
if(SOLVETYPE(get_problemtype()))
{ errbuf(1,english(1838));
errbuf(2,english(1839));
/* You might lose solutions by applying that law
without first verifying that condition. */
}
return 1;
}
}
u = tan1(x);
*next = reciprocal(u);
out:
HIGHLIGHT(*next);
strcpy(reason,"$$cot x = 1 / (tan x)$$");
return 0;
}
/*__________________________________________________________________*/
int tanrule(term t, term arg, term *next, char *reason)
/* tan x = sin x / cos x */
{ term u,v;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == TAN)
{ u = sin1(ARG(0,ARG(0,t)));
v = cos1(ARG(0,ARG(0,t)));
*next = make_fraction(make_power(u,ARG(1,t)),make_power(v,ARG(1,t)));
goto out;
}
if(f == '*')
return apply_aux(tanrule,t,arg,next,reason);
if(f != TAN)
return 1;
*next = make_fraction(sin1(ARG(0,t)), cos1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$tan x = (sin x)/ (cos x)$$");
return 0;
}
/*__________________________________________________________________*/
int tanrule2(term t, term arg, term *next, char *reason)
/* sin x / cos x = tan x (not used in auto mode) */
{ term num,denom,p,q,r,trash;
int i,err;
unsigned short n;
if (FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom)==COS)
{ err = cancel(num,sin1(ARG(0,denom)),&trash,&p);
if(err)
return 1;
q = tan1(ARG(0,denom));
HIGHLIGHT(q);
*next = product(p,q);
if(FUNCTOR(*next) == '*')
sortargs(*next);
}
else if(FUNCTOR(denom) == '*')
{ n = ARITY(denom);
for(i=0;i<n;i++)
{ if(FUNCTOR(ARG(i,denom))==COS)
break;
}
if(i==n)
return 1;
cancel(denom,ARG(i,denom),&trash,&r);
err = cancel(num,sin1(ARG(0,ARG(i,denom))),&trash,&p);
if(err)
return 1;
q = tan1(ARG(i,denom));
HIGHLIGHT(q);
*next = make_fraction(product(q,p),r);
if(FUNCTOR(ARG(0,*next))== '*')
sortargs(ARG(0,*next));
}
else if (FUNCTOR(denom) == '^' && FUNCTOR(ARG(0,denom)) == COS &&
FUNCTOR(num) == '^' && FUNCTOR(ARG(0,num)) == SIN &&
equals(ARG(0,ARG(0,num)), ARG(0,ARG(0,denom))) &&
equals(ARG(1,num),ARG(1,denom))
)
{ *next = make_power(tan1(ARG(0,ARG(0,num))),ARG(1,num));
HIGHLIGHT(*next);
}
else
return 1;
strcpy(reason,"$$(sin x) / (cos x) = tan x$$");
return 0;
}
/*__________________________________________________________________*/
int recip_aux(unsigned short f, unsigned short g, term t, term *next)
/* apply rule 1/f(x) = g(x) in a fraction; example:
recip_aux(COS, SEC, a/(b cos^2 x), &ans)
produces ans = (a sec^2 x)/b.
Also works on the integrand of an integral.
Return 0 for success, 1 for failure.
*/
{ term num,denom,p,q,trash,u,newdenom;
int i,err;
unsigned short n;
unsigned short path[5];
if(FUNCTOR(t) == INTEGRAL)
{ u = ARG(0,t);
err = recip_aux(f,g,u,&q);
if(err)
return 1;
if(ARITY(t) == 2)
*next = integral(q,ARG(1,t));
else
*next = definite_integral(q,ARG(1,t),ARG(2,t),ARG(3,t));
path[0] = INTEGRAL;
path[1] = 1;
path[2] = 0;
set_pathtail(path);
switch(f)
{ case COS:
SetShowStepOperation(secrule2);
break;
case SIN:
SetShowStepOperation(cscrule2);
break;
case TAN:
SetShowStepOperation(tanrecip);
break;
case COT:
SetShowStepOperation(cotrecip);
break;
case SEC:
SetShowStepOperation(secrecip);
break;
case CSC:
SetShowStepOperation(cscrecip);
break;
}
return 0;
}
if(!FRACTION(t))
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom)==f)
{ q = make_term(g,1);
ARGREP(q,0,ARG(0,denom));
HIGHLIGHT(q);
*next = product(num,q);
if(FUNCTOR(*next) == '*')
sortargs(*next);
return 0;
}
if(FUNCTOR(denom) == '^' && FUNCTOR(ARG(0,denom)) == f)
{ q = make_term(g,1);
ARGREP(q,0,ARG(0,ARG(0,denom)));
*next = product(num,make_power(q,ARG(1,denom)));
if(FUNCTOR(*next) == '*')
sortargs(*next);
return 0;
}
if(FUNCTOR(denom) == '*')
{ n = ARITY(denom);
for(i=0;i<n;i++)
{ u = ARG(i,denom);
if(FUNCTOR(u)==f)
break;
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == f)
break;
}
if(i==n)
return 1;
cancel(denom,u,&trash,&newdenom);
if(FUNCTOR(u) == f)
{ q = make_term(g,1);
ARGREP(q,0,ARG(0,u));
}
else
{ p = make_term(g,1);
ARGREP(p,0,ARG(0,ARG(0,u)));
q = make_power(p,ARG(1,u));
}
HIGHLIGHT(q);
*next = make_fraction(product(q,num),newdenom);
if(FUNCTOR(ARG(0,*next))== '*')
sortargs(ARG(0,*next));
return 0;
}
return 1;
}
/*__________________________________________________________________*/
static int recip_aux2(unsigned short f, unsigned short g, unsigned short h, term t, term *next)
/* apply rule 1/f(x) = g(x)/h(x) in a fraction; example:
recip_aux(TAN, COS, SIN, a/(b tan^2 x), &ans)
produces ans = (a cos^2 x)/(b sin^2 x).
Also works on the integrand of an integral.
Return 0 for success, 1 for failure.
*/
{ term num,denom,p,q,trash,u,newnum,newdenom;
int i,err;
unsigned short n;
unsigned short path[5];
if(FUNCTOR(t) == INTEGRAL)
{ u = ARG(0,t);
err = recip_aux2(f,g,h,u,&q);
if(err)
return 1;
if(ARITY(t) == 2)
*next = integral(q,ARG(1,t));
else
*next = definite_integral(q,ARG(1,t),ARG(2,t),ARG(3,t));
path[0] = INTEGRAL;
path[1] = 1;
path[2] = 0;
set_pathtail(path);
switch(f)
{ case TAN:
SetShowStepOperation(tanrecip2);
break;
case COT:
SetShowStepOperation(cotrecip2);
break;
}
return 0;
}
if(!FRACTION(t))
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom)==f)
{ q = make_term(g,1);
ARGREP(q,0,ARG(0,denom));
HIGHLIGHT(q);
newnum = product(num,q);
if(FUNCTOR(newnum) == '*')
sortargs(newnum);
newdenom = make_term(h,1);
ARGREP(newdenom,0,ARG(0,denom));
*next = make_fraction(newnum,newdenom);
return 0;
}
if(FUNCTOR(denom) == '^' && FUNCTOR(ARG(0,denom)) == f)
{ q = make_term(g,1);
ARGREP(q,0,ARG(0,ARG(0,denom)));
newnum = product(num,make_power(q,ARG(1,denom)));
if(FUNCTOR(newnum) == '*')
sortargs(newnum);
newdenom = make_term(h,1);
ARGREP(newdenom,0,ARG(0,ARG(0,denom)));
newdenom = make_power(newdenom,ARG(1,denom));
*next = make_fraction(newnum,newdenom);
return 0;
}
if(FUNCTOR(denom) == '*')
{ n = ARITY(denom);
for(i=0;i<n;i++)
{ u = ARG(i,denom);
if(FUNCTOR(u)==f)
break;
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == f)
break;
}
if(i==n)
return 1;
cancel(denom,u,&trash,&p);
if(FUNCTOR(u) == f)
{ q = make_term(g,1);
ARGREP(q,0,ARG(0,u));
}
else
{ p = make_term(g,1);
ARGREP(p,0,ARG(0,ARG(0,u)));
q = make_power(p,ARG(1,u));
}
HIGHLIGHT(q);
newnum = product(q,num);
if(FUNCTOR(newnum)== '*')
sortargs(newnum);
newdenom = make_term(h,1);
if(FUNCTOR(u) == f)
ARGREP(newdenom,0,ARG(0,u));
else
{ ARGREP(newdenom,0,ARG(0,ARG(0,u)));
newdenom = make_power(newdenom,ARG(1,u));
}
newdenom = product(newdenom,p);
if(FUNCTOR(newdenom) == '*')
sortargs(newdenom);
*next = make_fraction(newnum,newdenom);
return 0;
}
return 1;
}
/*__________________________________________________________________*/
int secrule2(term t, term arg, term *next, char *reason)
/* 1 / cos x = sec x */
/* also works directly on integral(1/cos x,x) and integral(1/cos^2 x,x) */
{ int err = recip_aux(COS,SEC,t,next);
if(err)
return 1;
strcpy(reason,"$$1 / (cos x) = sec x$$");
return 0;
}
/*__________________________________________________________________*/
int cscrule2(term t, term arg, term *next, char *reason)
/* 1 / sin x = csc x */
{ int err = recip_aux(SIN, CSC, t, next);
if(err)
return 1;
strcpy(reason,"$$1 / (sin x) = csc x$$");
return 0;
}
/*__________________________________________________________________*/
int tanrecip(term t, term arg, term *next, char *reason)
/* 1 / tan x = cot x */
{ int err = recip_aux(TAN, COT, t, next);
if(err)
return 1;
strcpy(reason,"$$1 / (tan u) = cot u$$");
return 0;
}
/*__________________________________________________________________*/
int tanrecip2(term t, term arg, term *next, char *reason)
/* 1 / tan x = cos x / sin x */
{ int err = recip_aux2(TAN, COS, SIN, t, next);
if(err)
return 1;
strcpy(reason,"$$1/(tan u) = (cos u)/(sin u)$$");
return 0;
}
/*__________________________________________________________________*/
int cotrecip2(term t, term arg, term *next, char *reason)
/* 1 / cot x = sin x / cos x */
{ int err = recip_aux2(COT, SIN, COS, t, next);
if(err)
return 1;
strcpy(reason,"$$1/(cot u) = (sin u)/(cos u)$$");
return 0;
}
/*__________________________________________________________________*/
int cotrecip(term t, term arg, term *next, char *reason)
/* 1 / cot u = tan u */
{ int err = recip_aux(COT, TAN, t, next);
if(err)
return 1;
strcpy(reason,"$$1 / (tan u) = (cot u)$$");
return 0;
}
/*__________________________________________________________________*/
int secrecip(term t, term arg, term *next, char *reason)
/* 1 / sec u = csc u */
{ int err = recip_aux(SEC, COS, t, next);
if(err)
return 1;
strcpy(reason,"$$1 / (sec u) = cos u$$");
return 0;
}
/*__________________________________________________________________*/
int cscrecip(term t, term arg, term *next, char *reason)
/* 1 / csc u = sin u */
{ int err = recip_aux(CSC, SIN, t, next);
if(err)
return 1;
strcpy(reason,"$$1 / (csc u) = sin u$$");
return 0;
}
/*__________________________________________________________________*/
int cotrule2(term t, term arg, term *next, char *reason)
/* cos x / sin x = cot x */
{ term num,denom,p,q,r,trash;
int i,err;
unsigned short n;
if (FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom)==SIN)
{ err = cancel(num,cos1(ARG(0,denom)),&trash,&p);
if(err)
return 1;
q = cot1(ARG(0,denom));
HIGHLIGHT(q);
*next = product(p,q);
if(FUNCTOR(*next) == '*')
sortargs(*next);
}
else if(FUNCTOR(denom) == '*')
{ n = ARITY(denom);
for(i=0;i<n;i++)
{ if(FUNCTOR(ARG(i,denom))==SIN)
break;
}
if(i==n)
return 1;
cancel(denom,ARG(i,denom),&trash,&r);
err = cancel(num,cos1(ARG(0,ARG(i,denom))),&trash,&p);
if(err)
return 1;
copy(cot1(ARG(0,ARG(i,denom))),&q); /* avoid DAGs */
HIGHLIGHT(q);
*next = make_fraction(product(q,p),r);
if(FUNCTOR(ARG(0,*next))== '*')
sortargs(ARG(0,*next));
}
else if (FUNCTOR(denom) == '^' && FUNCTOR(ARG(0,denom)) == SIN &&
FUNCTOR(num) == '^' && FUNCTOR(ARG(0,num)) == COS &&
equals(ARG(0,ARG(0,num)), ARG(0,ARG(0,denom))) &&
equals(ARG(1,num),ARG(1,denom))
)
{ *next = make_power(cot1(ARG(0,ARG(0,num))),ARG(1,num));
HIGHLIGHT(*next);
}
else
return 1;
strcpy(reason,"$$(cos x) / (sin x) = cot x$$");
return 0;
}
/*__________________________________________________________________*/
int cottosincos(term t, term arg, term *next, char *reason)
/* cot x = cos x / sin x */
{ term u;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == COT)
{ u = ARG(0,ARG(0,t));
*next = make_fraction(
make_power(cos1(u),ARG(1,t)),
make_power(sin1(u),ARG(1,t))
);
goto out;
}
if(f == '*')
return apply_aux(cottosincos,t,arg,next,reason);
if(f != COT)
return 1;
*next = make_fraction(cos1(ARG(0,t)), sin1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$cot x = (cos x) / (sin x)$$");
return 0;
}
/*__________________________________________________________________*/
int cottocscsec(term t, term arg, term *next, char *reason)
/* cot x = csq x / sec x */
{ term u;
unsigned short f = FUNCTOR(t);
if(f == '^' && INTEGERP(ARG(1,t)) && FUNCTOR(ARG(0,t)) == COT)
{ u = ARG(0,ARG(0,t));
*next = make_fraction(
make_power(csc1(u),ARG(1,t)),
make_power(sec1(u),ARG(1,t))
);
goto out;
}
if(f == '*')
return apply_aux(cottocscsec,t,arg,next,reason);
if(f != COT)
return 1;
*next = make_fraction(csc1(ARG(0,t)), sec1(ARG(0,t)));
out:
HIGHLIGHT(*next);
strcpy(reason,"$$cot x = (csc x) / (sec x)$$");
return 0;
}
/*__________________________________________________________________*/
int sinodd(term t, term arg, term *next, char *reason)
/* sin(-u) = -sin u */
{ if(FUNCTOR(t) != SIN)
return 1;
if(FUNCTOR(ARG(0,t)) != '-')
return 1;
*next = tnegate(sin1(ARG(0,ARG(0,t))));
HIGHLIGHT(*next);
strcpy(reason,"$$sin(-u) = -sin u$$");
return 0;
}
/*__________________________________________________________________*/
int coseven(term t, term arg, term *next, char *reason)
/* cos(-u) = cos u */
{ if(FUNCTOR(t) != COS)
return 1;
if(FUNCTOR(ARG(0,t)) != '-')
return 1;
*next = cos1(ARG(0,ARG(0,t)));
HIGHLIGHT(*next);
strcpy(reason,"$$cos(-u) = cos u$$");
return 0;
}
/*__________________________________________________________________*/
int tanodd(term t, term arg, term *next, char *reason)
/* tan(-u) = -tan u */
{ if(FUNCTOR(t) != TAN)
return 1;
if(FUNCTOR(ARG(0,t)) != '-')
return 1;
*next = tnegate(tan1(ARG(0,ARG(0,t))));
HIGHLIGHT(*next);
strcpy(reason,"$$tan(-u) = -tan u$$");
return 0;
}
/*__________________________________________________________________*/
int cotodd(term t, term arg, term *next, char *reason)
/* cot(-u) = -cot u */
{ if(FUNCTOR(t) != COT)
return 1;
if(FUNCTOR(ARG(0,t)) != '-')
return 1;
*next = tnegate(cot1(ARG(0,ARG(0,t))));
HIGHLIGHT(*next);
strcpy(reason,"$$cot(-u) = -cot u$$");
return 0;
}
/*__________________________________________________________________*/
int cscodd(term t, term arg, term *next, char *reason)
/* csc(-u) = -csc u */
{ if(FUNCTOR(t) != CSC)
return 1;
if(FUNCTOR(ARG(0,t)) != '-')
return 1;
*next = tnegate(csc1(ARG(0,ARG(0,t))));
HIGHLIGHT(*next);
strcpy(reason,"$$csc(-u) = -csc u$$");
return 0;
}
/*__________________________________________________________________*/
int seceven(term t, term arg, term *next, char *reason)
/* sec(-u) = sec u */
{ if(FUNCTOR(t) != SEC)
return 1;
if(FUNCTOR(ARG(0,t)) != '-')
return 1;
*next = sec1(ARG(0,ARG(0,t)));
HIGHLIGHT(*next);
strcpy(reason,"$$sec(-u) = sec u$$");
return 0;
}
/*__________________________________________________________________*/
int costosin(term t, term arg, term *next, char *reason)
/* cos(\pi /2-\theta) = sin \theta */
{ term u,theta;
if(FUNCTOR(t) != COS)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!equals(ARG(0,u),piover2))
return 1;
theta = ARG(0,ARG(1,u));
*next = sin1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$cos(\\pi/2-\\theta) = sin \\theta$");
return 0;
}
/*__________________________________________________________________*/
int sintocos(term t, term arg, term *next, char *reason)
/* sin(\pi /2-\theta) = cos \theta */
{ term u,theta;
if(FUNCTOR(t) != SIN)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!equals(ARG(0,u),piover2))
return 1;
theta = ARG(0,ARG(1,u));
*next = cos1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$sin(\\pi/2-\\theta) = cos \\theta$");
return 0;
}
/*__________________________________________________________________*/
int tantocot(term t, term arg, term *next, char *reason)
/* tan(pi/2-theta) = cot theta */
{ term u,theta;
if(FUNCTOR(t) != TAN)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!equals(ARG(0,u),piover2))
return 1;
theta = ARG(0,ARG(1,u));
*next = cot1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$tan(\\pi/2-\\theta) = cot \\theta$");
return 0;
}
/*__________________________________________________________________*/
int cotcomplement(term t, term arg, term *next, char *reason)
/* cot(\pi /2-\theta) = tan \theta */
{ term u,theta;
if(FUNCTOR(t) != COT)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!equals(ARG(0,u),piover2))
return 1;
theta = ARG(0,ARG(1,u));
*next = tan1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$cot(\\pi/2-\\theta) = tan \\theta$");
return 0;
}
/*__________________________________________________________________*/
int seccomplement(term t, term arg, term *next, char *reason)
/* sec(pi/2- theta) = csc theta */
{ term u,theta;
if(FUNCTOR(t) != SEC)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!equals(ARG(0,u),piover2))
return 1;
theta = ARG(0,ARG(1,u));
*next = csc1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$sec(\\pi/2-\\theta) = csc \\theta$");
return 0;
}
/*__________________________________________________________________*/
int csccomplement(term t, term arg, term *next, char *reason)
/* csc(\pi /2-\theta) = sec \theta */
{ term u,theta;
if(FUNCTOR(t) != CSC)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!equals(ARG(0,u),piover2))
return 1;
theta = ARG(0,ARG(1,u));
*next = sec1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$csc(\\pi/2-\\theta) = sec \\theta$");
return 0;
}
/*__________________________________________________________________*/
#define NINETYDEGREES(x) (FUNCTOR(x) == DEG && ISINTEGER(ARG(0,x)) && INTDATA(ARG(0,x)) == 90)
/*__________________________________________________________________*/
int costosindeg(term t, term arg, term *next, char *reason)
/* cos(90\\deg -\theta) = sin \theta */
{ term u,theta;
if(FUNCTOR(t) != COS)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!NINETYDEGREES(ARG(0,u)))
return 1;
theta = ARG(0,ARG(1,u));
*next = sin1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$cos(90\\deg -\\theta) = sin \\theta$");
return 0;
}
/*__________________________________________________________________*/
int sintocosdeg(term t, term arg, term *next, char *reason)
/* sin(90\\deg -theta) = cos theta */
{ term u,theta;
if(FUNCTOR(t) != SIN)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!NINETYDEGREES(ARG(0,u)))
return 1;
theta = ARG(0,ARG(1,u));
*next = cos1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$sin(90\\deg -\\theta) = cos \\theta$");
return 0;
}
/*__________________________________________________________________*/
int tantocotdeg(term t, term arg, term *next, char *reason)
/* tan(90\\deg -\theta) = cot \theta */
{ term u,theta;
if(FUNCTOR(t) != TAN)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!NINETYDEGREES(ARG(0,u)))
return 1;
theta = ARG(0,ARG(1,u));
*next = cot1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$tan(90\\deg -\\theta) = cot \\theta$");
return 0;
}
/*__________________________________________________________________*/
int cotcomplementdeg(term t, term arg, term *next, char *reason)
/* cot(90\\deg -\theta) = tan \theta */
{ term u,theta;
if(FUNCTOR(t) != COT)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!NINETYDEGREES(ARG(0,u)))
return 1;
theta = ARG(0,ARG(1,u));
*next = tan1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$cot(90\\deg -\\theta) = tan \\theta$");
return 0;
}
/*__________________________________________________________________*/
int seccomplementdeg(term t, term arg, term *next, char *reason)
/* sec(90\\deg -\theta) = csc \theta */
{ term u,theta;
if(FUNCTOR(t) != SEC)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!NINETYDEGREES(ARG(0,u)))
return 1;
theta = ARG(0,ARG(1,u));
*next = csc1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$sec(90\\deg -\\theta) = csc \\theta$");
return 0;
}
/*__________________________________________________________________*/
int csccomplementdeg(term t, term arg, term *next, char *reason)
/* csc(90\\deg -theta) = sec theta */
{ term u,theta;
if(FUNCTOR(t) != CSC)
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) != 2)
return 1;
if(FUNCTOR(ARG(1,u)) != '-')
return 1;
if(!NINETYDEGREES(ARG(0,u)))
return 1;
theta = ARG(0,ARG(1,u));
*next = sec1(theta);
HIGHLIGHT(*next);
strcpy(reason,"$csc(90\\deg -\\theta) = sec \\theta$");
return 0;
}
/*__________________________________________________________________*/
int sincosop(term t, term arg, term *next, char *reason)
/* sin x cos y = (1/2)[sin(x+y)+sin(x-y)] */
{ term lhs,rhs,a[2],temp,v;
int err;
int mathmode;
if(FUNCTOR(t) != '*')
return 1;
lhs = product(sin1(var0),cos1(var1));
rhs = sum(sin1(sum(var0,var1)),sin1(sum(var0,tnegate(var1))));
err = match(t,lhs,rhs,a,&temp); /* instantiate a and temp */
if(err)
return 1;
mathmode = get_mathmode();
if(mathmode == AUTOMODE && get_intflag())
/* don't use this on an integrand unless the new arguments
of the trig functions simplify by collecting terms */
{ term u,v;
u = sum(a[0],a[1]);
if(FUNCTOR(a[0]) == '+' || FUNCTOR(a[1]) == '+')
u = topflatten(u);
if(!collect(u,&v))
return 1;
}
if(mathmode == AUTOMODE && equals(a[0],a[1]))
/* don't use it on sin x cos x; this screws up the integrals
of sin x cos x and of x cos x sin x */
return 1;
polyval(temp,&v); /* sin(3t-t) => sin 2t and so on */
*next = product(make_fraction(one,two),v);
HIGHLIGHT(*next);
strcpy(reason,"$sin x cos y = \\onehalf [sin(x+y)+sin(x-y)]$");
inhibit(sumofcos);
inhibit(sumofsin);
return 0;
}
/*__________________________________________________________________*/
int cossin(term t, term arg, term *next, char *reason)
/* cos x sin y = (1/2)[sin(x+y)-sin(x-y) */
{ term lhs,rhs,a[2],temp,v;
int err;
int mathmode;
if(FUNCTOR(t) != '*')
return 1;
lhs = product(sin1(var1),cos1(var0));
rhs = sum(sin1(sum(var0,var1)),tnegate(sin1(sum(var0,tnegate(var1)))));
err = match(t,lhs,rhs,a,&temp); /* instantiate a and temp */
if(err)
return 1;
mathmode = get_mathmode();
if(mathmode == AUTOMODE && get_intflag())
/* don't use this on an integrand unless the new arguments
of the trig functions simplify by collecting terms */
{ term u,v;
u = sum(a[0],a[1]);
if(FUNCTOR(a[0]) == '+' || FUNCTOR(a[1]) == '+')
u = topflatten(u);
if(!collect(u,&v))
return 1;
}
if(mathmode == AUTOMODE && equals(a[0],a[1]))
/* don't use it on sin x cos x; this screws up the integrals
of sin x cos x and of x cos x sin x */
return 1;
polyval(temp,&v); /* sin(3t-t) => sin 2t and so on */
*next = product(make_fraction(one,two),v);
HIGHLIGHT(*next);
strcpy(reason,"$cos x sin y = \\onehalf [sin(x+y)-sin(x-y)]$");
inhibit(sumofcos);
inhibit(sumofsin);
return 0;
}
/*__________________________________________________________________*/
int reversedoublesin(term t, term arg, term *next, char *reason)
/* cos x sin x = \\onehalf sin 2x */
{ term lhs,rhs,a[2],temp,u;
int err,i;
unsigned short n;
if(FUNCTOR(t) != '*')
return 1;
lhs = product(sin1(var0),cos1(var0));
rhs = sin1(product(two,var0));
err = match(t,lhs,rhs,a,&temp); /* instantiate a and temp */
if(err)
return 1;
u = product(make_fraction(one,two),temp);
if(ARITY(t) == 2)
*next = u;
else
{ err = value(u,next); /* don't produce 1/2 2 sin 2\theta */
if(err == 1)
*next = u;
if(FUNCTOR(*next) == '*' && ONE(ARG(0,*next)))
/* Don't produce 1 sin 2\theta */
{ n = ARITY(*next);
if(n == 2)
*next = ARG(1,*next);
else
{ u = *next;
*next = make_term('*',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(*next,i,ARG(i+1,u));
}
}
}
HIGHLIGHT(*next);
if(FUNCTOR(*next) == '*' && FRACTION(ARG(0,*next)))
strcpy(reason,"$cos \\theta sin \\theta = \\onehalf sin 2\\theta$");
else
strcpy(reason,"$2cos \\theta sin \\theta = sin 2\\theta$");
return 0;
}
/*__________________________________________________________________*/
int reversedoublesin2(term t, term arg, term *next, char *reason)
/* 2 cos x sin x = sin 2x */
{ return reversedoublesin(t,arg,next,reason);
}
/*__________________________________________________________________*/
int sinsin(term t, term arg, term *next, char *reason)
/* sin x sin y = \\onehalf [cos(x-y)-cos(x+y)] */
{ term lhs,rhs,a[2],temp,v;
int err;
if(FUNCTOR(t) != '*')
return 1;
lhs = product(sin1(var0),sin1(var1));
rhs = sum(cos1(sum(var0,tnegate(var1))),tnegate(cos1(sum(var0,var1))));
err = match(t,lhs,rhs,a,&temp); /* instantiate a and temp */
if(err)
return 1;
if(get_mathmode() == AUTOMODE && get_intflag())
/* don't use this on an integrand unless the new arguments
of the trig functions simplify by collecting terms */
{ term u,v;
u = sum(a[0],a[1]);
if(FUNCTOR(a[0]) == '+' || FUNCTOR(a[1]) == '+')
u = topflatten(u);
if(!collect(u,&v))
return 1;
}
polyval(temp,&v); /* sin(3t-t) => sin(2t) and so on */
v = trigsimp(v);
*next = product(make_fraction(one,two),v);
HIGHLIGHT(*next);
strcpy(reason,"$sin x sin y = \\onehalf [cos(x-y)-cos(x+y)]$");
inhibit(sumofcos);
inhibit(sumofsin);
inhibit(difofcos);
return 0;
}
/*__________________________________________________________________*/
int coscos(term t, term arg, term *next, char *reason)
/* cos x cos y = \\onehalf [cos(x+y)+cos(x-y) */
{ term lhs,rhs,a[2],temp,v;
int err;
if(FUNCTOR(t) != '*')
return 1;
lhs = product(cos1(var0),cos1(var1));
rhs = sum(cos1(sum(var0,var1)),cos1(sum(var0,tnegate(var1))));
err = match(t,lhs,rhs,a,&temp); /* instantiate a and temp */
if(err)
return 1;
if(get_mathmode() == AUTOMODE && get_intflag())
/* don't use this on an integrand unless the new arguments
of the trig functions simplify by collecting terms */
{ term u,v;
u = sum(a[0],a[1]);
if(FUNCTOR(a[0]) == '+' || FUNCTOR(a[1]) == '+')
u = topflatten(u);
if(!collect(u,&v))
return 1;
}
polyval(temp,&v); /* sin(3t-t) => sin 2t and so on */
v = trigsimp(v);
*next = product(make_fraction(one,two),v);
HIGHLIGHT(*next);
strcpy(reason,"$cos x cos y = \\onehalf [cos(x+y)+cos(x-y)]$");
inhibit(sumofcos);
inhibit(sumofsin);
inhibit(difofcos);
return 0;
}
/*__________________________________________________________________*/
int checknumerically(term t, term arg, term *next, char *reason)
/* try to refute a trig identity by plugging in a value */
/* This operator doesn't even check the result, it just calculates the
numerical values the user has requested */
{ term q;
int err,i,k;
double z[32];
char buffer[81];
double lhs,rhs;
int nvariables;
term *atomlist;
double savevals[32];
int autoflag = (FUNCTOR(arg) == ILLEGAL);
if(autoflag) /* got here in auto mode */
arg = zero;
if(FUNCTOR(t) != '=')
return 1;
/* Theoretically check_arg ensures that arg is evaluable by deval,
but let's check it again here. */
if(FUNCTOR(arg) == AND)
{ for(i=0;i<ARITY(arg);i++)
{ if(!seminumerical(ARG(i,arg)))
return 1;
}
}
else if(!seminumerical(arg))
return 1;
nvariables = real_variables(t,&atomlist);
if(nvariables == 0)
{ free2(atomlist);
return 1;
}
if(autoflag && nvariables > 1)
return 1;
if(nvariables == 1)
{ savevals[0] = VALUE(atomlist[0]);
deval(arg,z);
SETVALUE(atomlist[0],z[0]);
}
if(nvariables > 32)
{ free2(atomlist);
return 1; /* this will never happen, nobody is going to
enter 32 numbers. */
}
else if(FUNCTOR(arg) == AND && ARITY(arg) == nvariables)
{ for(i=0;i<nvariables; i++)
{ deval(ARG(i,arg),&z[i]);
savevals[i] = VALUE(atomlist[i]);
SETVALUE(atomlist[i],z[i]);
}
}
err = deval(ARG(0,t),&lhs);
if(err || lhs == BADVAL)
{ errbuf(0, english(646)); /* Can't evaluate left side */
err = 1;
goto out;
}
err = deval(ARG(1,t),&rhs);
if(err || rhs == BADVAL)
{ errbuf(0, english(647)); /* Can't evaluate right side */
err = 1;
goto out;
}
if(autoflag)
{ if(fabs(lhs-rhs) < 0.0001)
/* Make SURE that roundoff error doesn't produce a false
refutation; anyway the difference in values should be
visible to the user who sees only four decimal places. */
{ /* not refuted at zero, try pi/2 and 1 */
for(k=0;k<2;k++)
{ arg = k ? one : make_fraction(pi_term,two);
subst(arg,atomlist[0],t,&q);
err = deval(ARG(0,q),&lhs);
if(err)
continue;
err = deval(ARG(1,q),&rhs);
if(err)
continue;
if(fabs(lhs) > 1.0e7 || fabs(rhs) > 1.0e7)
/* probably it's a singularity that doesn't
show as a BADVAL because of roundoff error */
continue;
if(fabs(lhs-rhs) >= .0001)
break; /* refuted */
}
if(k == 2)
{ SETVALUE(atomlist[0],savevals[0]);
free2(atomlist);
return 1; /* not refuted */
}
}
}
*next = equation(make_double(lhs),make_double(rhs));
HIGHLIGHT(*next);
strcpy(reason, english(648)); /* evaluate at */
err = mstring(arg,buffer);
if(err)
strcat(reason, english(649)); /* point */
else
{ k = (int) strlen(buffer);
if(k<10)
strcat(reason,buffer);
else
strcat(reason, english(649)); /* point */
}
err = 0;
out:
for(i=0;i<nvariables;i++)
SETVALUE(atomlist[i],savevals[i]);
free2(atomlist);
return err;
}
/*__________________________________________________________________*/
int sumofsin(term t, term arg, term *next, char *reason)
/* sin x + sin y = 2 sin \\onehalf (x+y) cos \\onehalf (x-y) */
{ term lhs,rhs,a[2];
term u,temp,p,q;
int err,saveit,problemtype;
unsigned short n;
if(FUNCTOR(t) != '+')
return 1;
n = ARITY(t);
problemtype = get_problemtype();
if(n > 2)
{ err = sumtrig_aux(sumofsin,t,arg,next,reason);
if(!err)
return 0;
if(get_mathmode() == AUTOMODE)
return 1;
}
lhs = sum(sin1(var0),sin1(var1));
rhs = product3(two,sin1(make_fraction(sum(var0,var1),two)),cos1(make_fraction(sum(var0,tnegate(var1)),two)));
err = match(t,lhs,rhs,a,&u); /* instantiate a and u */
if(err)
{ destroy_term(lhs);
destroy_term(rhs);
return 1;
}
saveit = get_polyvalfunctionflag();
set_polyvalfunctionflag(1);
if(get_mathmode() == AUTOMODE &&
get_currenttopic() != _trig_factor &&
!SOLVETYPE(problemtype)
)
{ /* don't create sin(3x/2) from sin(2x)-sin x */
polyval(sum(a[0],a[1]),&temp);
if(seminumerical(temp))
err = 0;
else
err = cancel(temp,two,&p,&q);
if(err)
{ set_polyvalfunctionflag(saveit);
return 1;
}
}
adjust_polyvalfunctionflag(u);
polyval(u,next);
set_polyvalfunctionflag(saveit);
clear_already(next); /* e.g. sin(pi/2) has been marked 'ALREADY' since
polyvalfunctionflag was off */
HIGHLIGHT(*next);
strcpy(reason,"$sin x + sin y = 2 sin\\onehalf (x+y) cos\\onehalf (x-y)$");
if(FUNCTOR(*next) == '*' && ARITY(*next) == 3 && !seminumerical(ARG(1,*next)))
/* I think it has to be of that form, but I'm worried that polyval might
simplify it somehow for some input */
PROTECT(ARG(1,*next));
/* prevent sinhalf, coshalf working on it, or
in case it comes out something like 2 cos 2x sin 4x
as it will if the input is sin 6x + sin 2x, prevent
doublesin, doublecos etc. working on it, until it
can be cancelled with a similar term in the numerator.
If this doesn't happen, of course on pass 2 the protections
will be removed. */
inhibit(sinsin);
inhibit(coscos);
inhibit(sincosop);
inhibit(cossin);
return 0;
}
/*__________________________________________________________________*/
int difofsin(term t, term arg, term *next, char *reason)
/* sin x - sin y = 2 sin \\onehalf (x-y) cos \\onehalf (x+y) */
{ term lhs,rhs,a[2];
term u,temp,p,q;
int err,saveit;
unsigned short n;
int problemtype;
if(FUNCTOR(t) != '+')
return 1;
n = ARITY(t);
problemtype = get_problemtype();
if(n > 2)
{ err = sumtrig_aux(difofsin,t,arg,next,reason);
if(!err)
return 0;
if(get_mathmode() == AUTOMODE)
return 1;
}
lhs = sum(sin1(var0),tnegate(sin1(var1)));
rhs = product3(two,sin1(make_fraction(sum(var0,tnegate(var1)),two)),cos1(make_fraction(sum(var0,var1),two)));
err = match(t,lhs,rhs,a,&u); /* instantiate a and u */
if(err)
{ destroy_term(lhs);
destroy_term(rhs);
return 1;
}
saveit = get_polyvalfunctionflag();
set_polyvalfunctionflag(1);
if(get_mathmode() == AUTOMODE &&
get_currenttopic() != _trig_factor &&
!SOLVETYPE(problemtype)
)
{ /* don't create sin(3x/2) from sin(2x)-sin x */
polyval(sum(a[0],a[1]),&temp);
if(seminumerical(temp))
err = 0;
else
err = cancel(temp,two,&p,&q);
if(err)
{ set_polyvalfunctionflag(saveit);
return 1;
}
}
adjust_polyvalfunctionflag(u);
polyval(u,next);
set_polyvalfunctionflag(saveit);
clear_already(next); /* e.g. sin(pi/2) has been marked 'ALREADY' since
polyvalfunctionflag was off */
HIGHLIGHT(*next);
strcpy(reason,"$sin x - sin y = 2 sin\\onehalf (x-y) cos\\onehalf (x+y)$");
if(FUNCTOR(*next) == '*' && ARITY(*next) == 3 && !seminumerical(ARG(1,*next)))
/* I think it has to be, but I'm worried that polyval might
simplify it somehow for some input */
PROTECT(ARG(1,*next));
inhibit(sinsin);
inhibit(coscos);
inhibit(sincosop);
inhibit(cossin);
return 0;
}
/*__________________________________________________________________*/
int sumofcos(term t, term arg, term *next, char *reason)
/* cos x + cos y = 2 cos \\onehalf (x+y) cos \\onehalf (x-y) */
{ term lhs,rhs,a[2],u,temp,p,q;
int err,saveit,problemtype;
unsigned short n;
if(FUNCTOR(t) != '+')
return 1;
n = ARITY(t);
problemtype = get_problemtype();
if(n > 2)
{ err = sumtrig_aux(sumofcos,t,arg,next,reason);
if(!err)
return 0;
if(get_mathmode() == AUTOMODE)
return 1;
}
lhs = sum(cos1(var0),cos1(var1));
rhs = product3(two,cos1(make_fraction(sum(var0,var1),two)),cos1(make_fraction(sum(var0,tnegate(var1)),two)));
err = match(t,lhs,rhs,a,&u); /* instantiate a and u */
if(err)
{ destroy_term(lhs);
destroy_term(rhs);
return 1;
}
saveit = get_polyvalfunctionflag();
set_polyvalfunctionflag(1);
if(get_mathmode() == AUTOMODE &&
get_currenttopic() != _trig_factor &&
!SOLVETYPE(problemtype)
)
{ /* don't create sin(3x/2) from sin(2x)-sin x */
polyval(sum(a[0],a[1]),&temp);
if(seminumerical(temp))
err = 0;
else
err = cancel(temp,two,&p,&q);
if(err)
{ set_polyvalfunctionflag(saveit);
return 1;
}
}
adjust_polyvalfunctionflag(u);
polyval(u,next);
set_polyvalfunctionflag(saveit);
clear_already(next); /* e.g. sin(pi/2) has been marked 'ALREADY' since
polyvalfunctionflag was off */
HIGHLIGHT(*next);
strcpy(reason,"$cos x + cos y = 2 cos\\onehalf (x+y) cos\\onehalf (x-y)$");
if(FUNCTOR(*next) == '*' && ARITY(*next) == 3 && !seminumerical(ARG(1,*next)))
/* I think it has to be, but I'm worried that polyval might
simplify it somehow for some input */
PROTECT(ARG(1,*next));
inhibit(sinsin);
inhibit(coscos);
inhibit(sincosop);
inhibit(cossin);
return 0;
}
/*__________________________________________________________________*/
int difofcos(term t, term arg, term *next, char *reason)
/* cos x - cos y = -2 sin \\onehalf (x+y) sin \\onehalf (x-y) */
{ term lhs,rhs,a[2],u,temp,p,q;
int err,saveit,problemtype;
unsigned short n;
if(FUNCTOR(t) != '+')
return 1;
n = ARITY(t);
problemtype = get_problemtype();
if(n > 2)
{ err = sumtrig_aux(difofcos,t,arg,next,reason);
if(!err)
return 0;
if(get_mathmode() == AUTOMODE)
return 1;
}
lhs = sum(cos1(var0),tnegate(cos1(var1)));
rhs = tnegate(product3(two,sin1(make_fraction(sum(var0,var1),two)),sin1(make_fraction(sum(var0,tnegate(var1)),two))));
err = match(t,lhs,rhs,a,&u); /* instantiate a and u */
if(err)
{ destroy_term(lhs);
destroy_term(rhs);
return 1;
}
saveit = get_polyvalfunctionflag();
set_polyvalfunctionflag(1);
if(get_mathmode() == AUTOMODE &&
get_currenttopic() != _trig_factor &&
!SOLVETYPE(problemtype)
)
{ /* don't create sin(3x/2) from sin(2x)-sin x */
polyval(sum(a[0],a[1]),&temp);
if(seminumerical(temp))
err = 0;
else
err = cancel(temp,two,&p,&q);
if(err)
{ set_polyvalfunctionflag(saveit);
return 1;
}
}
adjust_polyvalfunctionflag(u);
polyval(u,next);
set_polyvalfunctionflag(saveit);
clear_already(next); /* e.g. sin(pi/2) has been marked 'ALREADY' since
polyvalfunctionflag was off */
HIGHLIGHT(*next);
strcpy(reason,"$cos x - cos y = -2sin\\onehalf (x+y) sin\\onehalf (x-y)$");
if(NEGATIVE(*next) &&
FUNCTOR(ARG(0,*next)) == '*' &&
ARITY(ARG(0,*next)) == 3 &&
!seminumerical(ARG(1,ARG(0,*next)))
)
/* I think it has to be of that form , but I'm worried that polyval might
simplify it somehow for some input */
PROTECT(ARG(1,ARG(0,*next))); /* the sin(x+y) term */
inhibit(sinsin);
inhibit(coscos);
inhibit(sincosop);
inhibit(cossin);
return 0;
}
/*__________________________________________________________________*/
int sintocos2(term t, term arg, term *next, char *reason)
/* sin theta = cos(pi/2-theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
int savecomdenomflag;
if(FUNCTOR(t) != SIN)
return 1;
u = sum(make_fraction(pi_term,two),tnegate(ARG(0,t)));
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvalcomdenomflag(0);
polyval(u,&v);
set_polyvalcomdenomflag(savecomdenomflag);
*next = cos1(v);
HIGHLIGHT(*next);
strcpy(reason,"$sin \\theta = cos(\\pi/2-\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int costosin2(term t, term arg, term *next, char *reason)
/* cos theta = sin(pi/2-theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
int savecomdenomflag;
if(FUNCTOR(t) != COS)
return 1;
u = sum(make_fraction(pi_term,two),tnegate(ARG(0,t)));
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvalcomdenomflag(0);
polyval(u,&v);
set_polyvalcomdenomflag(savecomdenomflag);
*next = sin1(v);
HIGHLIGHT(*next);
strcpy(reason,"$cos \\theta = sin(\\pi/2-\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int tantocot2(term t, term arg, term *next, char *reason)
/* tan theta = cot(pi/2-theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
int savecomdenomflag;
if(FUNCTOR(t) != TAN)
return 1;
u = sum(make_fraction(pi_term,two),tnegate(ARG(0,t)));
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvalcomdenomflag(0);
polyval(u,&v);
set_polyvalcomdenomflag(savecomdenomflag);
*next = cot1(v);
HIGHLIGHT(*next);
strcpy(reason,"$tan \\theta = cot(\\pi/2-\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int cottotan2(term t, term arg, term *next, char *reason)
/* cot \theta = tan(\pi/2-\theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
int savecomdenomflag;
if(FUNCTOR(t) != COT)
return 1;
u = sum(make_fraction(pi_term,two),tnegate(ARG(0,t)));
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvalcomdenomflag(0);
polyval(u,&v);
set_polyvalcomdenomflag(savecomdenomflag);
*next = tan1(v);
HIGHLIGHT(*next);
strcpy(reason,"$cot \\theta = tan(\\pi/2-\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int sectocsc2(term t, term arg, term *next, char *reason)
/* sec theta = csc(pi/2-theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
int savecomdenomflag;
if(FUNCTOR(t) != SEC)
return 1;
u = sum(make_fraction(pi_term,two),tnegate(ARG(0,t)));
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvalcomdenomflag(0);
polyval(u,&v);
set_polyvalcomdenomflag(savecomdenomflag);
*next = csc1(v);
HIGHLIGHT(*next);
strcpy(reason,"$sec \\theta = csc(\\pi/2-\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int csctosec2(term t, term arg, term *next, char *reason)
/* csc theta = sec(pi/2-\theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
int savecomdenomflag;
if(FUNCTOR(t) != CSC)
return 1;
u = sum(make_fraction(pi_term,two),tnegate(ARG(0,t)));
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvalcomdenomflag(0);
polyval(u,&v);
set_polyvalcomdenomflag(savecomdenomflag);
*next = sec1(v);
HIGHLIGHT(*next);
strcpy(reason,"$csc \\theta = sec(\\pi/2-\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int sintocos2deg(term t, term arg, term *next, char *reason)
/* sin theta = cos(90\\deg -theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
if(FUNCTOR(t) != SIN)
return 1;
u = sum(deg1(make_int(90)),tnegate(ARG(0,t)));
polyval(u,&v);
*next = cos1(v);
HIGHLIGHT(*next);
strcpy(reason,"$sin \\theta = cos(90\\deg -\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int costosin2deg(term t, term arg, term *next, char *reason)
/* cos pi_term = sin(90\\deg -theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
if(FUNCTOR(t) != COS)
return 1;
u = sum(deg1(make_int(90)),tnegate(ARG(0,t)));
polyval(u,&v);
*next = sin1(v);
HIGHLIGHT(*next);
strcpy(reason,"$cos \\theta = sin(90\\deg -\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int tantocot2deg(term t, term arg, term *next, char *reason)
/* tan theta = cot(90\\deg -theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
if(FUNCTOR(t) != TAN)
return 1;
u = sum(deg1(make_int(90)),tnegate(ARG(0,t)));
polyval(u,&v);
*next = cot1(v);
HIGHLIGHT(*next);
strcpy(reason,"$tan \\theta = cot(90\\deg -\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int cottotan2deg(term t, term arg, term *next, char *reason)
/* cot theta = tan(90\\deg -theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
if(FUNCTOR(t) != COT)
return 1;
u = sum(deg1(make_int(90)),tnegate(ARG(0,t)));
polyval(u,&v);
*next = tan1(v);
HIGHLIGHT(*next);
strcpy(reason,"$cot \\theta = tan(90\\deg -\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int sectocsc2deg(term t, term arg, term *next, char *reason)
/* sec theta = csc(90\\deg -theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
if(FUNCTOR(t) != SEC)
return 1;
u = sum(deg1(make_int(90)),tnegate(ARG(0,t)));
polyval(u,&v);
*next = csc1(v);
HIGHLIGHT(*next);
strcpy(reason,"$sec \\theta = csc(90\\deg -\\theta)$");
return 0;
}
/*__________________________________________________________________*/
int csctosec2deg(term t, term arg, term *next, char *reason)
/* csc theta = sec(90\\deg -theta) */
/* Not used in automode; meant for use by term-selection */
{ term u,v;
if(FUNCTOR(t) != CSC)
return 1;
u = sum(deg1(make_int(90)),tnegate(ARG(0,t)));
polyval(u,&v);
*next = sec1(v);
HIGHLIGHT(*next);
strcpy(reason,"$csc \\theta = sec(90\\deg -\\theta)$");
return 0;
}
/*_________________________________________________________________*/
static int sumtrig_aux(actualop o, term t, term arg, term *next, char *reason)
/* o is either sumofsin, difofsin, sumofcos, or difofcos. t is a sum
of arity at least 3. Choose which two args of the sum to work on.
Choose two args such that the result will
content_factor. If this is not possible, return 1.
For example, in sin x + sin(3x) + sin(5x), apply it
to the last two args; using 'match' will mindlessly
choose the first two args, creating a term with args 2x.
Return 0 for success, with the result that should replace
t in *next, and in *reason, the reason string produced
by the operation.
*/
{ int i,j,k,err;
term p,q,r,u,v;
unsigned short n = ARITY(t);
assert(FUNCTOR(t) == '+');
for(i=0;i<n;i++)
{ for(j=i+1;j<n;j++)
{ p = sum(ARG(i,t),ARG(j,t));
err = (*o)(p,arg,&q,reason);
if(err)
continue;
r = make_term('+',(unsigned short)(n-1));
for(k=0;k<n-1;k++)
ARGREP(r,k,k<i ? ARG(k,t) : k==i? q : k < j ? ARG(k,t) : ARG(k+1,t));
err = content_factor(r,&u,&v);
if(!err)
break;
}
if(j < n)
break;
}
if(i < n)
{ *next = r;
/* Prevent e.g. sin 4x just created from being expanded
as a double angle before we can factor it. These
inhibitions are released by spliteqn2. */
inhibit(doublesin);
inhibit(doublecos1);
inhibit(doublecos2);
inhibit(doublecos3);
inhibit(doublecos4);
return 0;
}
return 1;
}
/*________________________________________________________________*/
static int trigrat_aux(term t, term arg, term *next)
/* If t is an integral of a fraction, multiply the num and denom
by arg and return the new integral. If t is a fraction,
multiply the num and denom by arg and return the new fraction.
Return 0 for success, 1 for wrong input.
*/
{ term num, denom,a,b,u,arg2;
if(FUNCTOR(t) == INTEGRAL && FRACTION(ARG(0,t)))
{ trigrat_aux(ARG(0,t),arg,&u);
*next = ARITY(t) == 2 ? integral(u,ARG(1,t)):
definite_integral(u,ARG(1,t),ARG(2,t),ARG(3,t));
return 0;
}
if(!FRACTION(t))
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(arg) == '+')
additive_sortargs(arg);
HIGHLIGHT(arg);
a = product(arg,num);
copy(arg,&arg2); /* avoid creating DAG's */
b = product(arg2,denom);
if(FUNCTOR(a) == '*')
sortargs(a);
if(FUNCTOR(b) == '*')
sortargs(b);
*next = make_fraction(a,b);
inhibit(cancelop); /* to be released by difofsquares */
inhibit(polyvalop); /* to be released by difofsquares */
inhibit(cancelgcd); /* to be released by difofsquares */
inhibit(cancelgcd); /* to be released by sinsquare2, sinsquare3,
sinsqtocossq, or cossqtosinsq. Note that
cancelgcd gets inhibited twice because the
result of this function has to survive two
automode steps without using cancelgcd.
*/
inhibit(apart); /* to be released by difofsquares */
inhibit(apartandcancel); /* ditto */
return 0;
}
/*__________________________________________________________________*/
int trigrationalizedenom1(term t, term arg, term *next, char *reason)
/* multiply num and denom by 1+cos x */
/* Works on an integral with a fraction for an integrand,
or directly on a fraction in menu mode or term selection mode
*/
{ term x;
int err;
if(FUNCTOR(t) != INTEGRAL)
return 1;
x = ARG(1,t);
arg = sum(one,cos1(x));
err = trigrat_aux(t,arg,next);
if(err)
return 1;
strcpy(reason, english(755)); /* mult num and denom by */
strcat(reason," ");
strcat(reason, "$1 + cos x$");
return 0;
}
/*__________________________________________________________________*/
int trigrationalizedenom4(term t, term arg, term *next, char *reason)
/* multiply num and denom by 1-cos x */
/* Works on an integral with a fraction for an integrand,
or directly on a fraction in menu mode or term selection mode
*/
{ term x;
int err;
if(FUNCTOR(t) != INTEGRAL)
return 1;
x = ARG(1,t);
arg = sum(one,tnegate(cos1(x)));
err = trigrat_aux(t,arg,next);
if(err)
return 1;
strcpy(reason, english(755)); /* mult num and denom by */
strcat(reason, " ");
strcat(reason, "$1 - cos x$");
return 0;
}
/*__________________________________________________________________*/
int trigrationalizedenom2(term t, term arg, term *next, char *reason)
/* multiply num and denom by 1+sin x */
/* Works on an integral with a fraction for an integrand,
or directly on a fraction in menu mode or term selection mode
*/
{ term x;
int err;
if(FUNCTOR(t) != INTEGRAL)
return 1;
x = ARG(1,t);
arg = sum(one,sin1(x));
err = trigrat_aux(t,arg,next);
if(err)
return 1;
strcpy(reason, english(755)); /* mult num and denom by */
strcat(reason, " ");
strcat(reason, "$1 + sin x$");
return 0;
}
/*__________________________________________________________________*/
int trigrationalizedenom5(term t, term arg, term *next, char *reason)
/* multiply num and denom by 1-sin x */
/* Works on an integral with a fraction for an integrand,
or directly on a fraction in menu mode or term selection mode
*/
{ term x;
int err;
if(FUNCTOR(t) != INTEGRAL)
return 1;
x = ARG(1,t);
arg = sum(one,tnegate(sin1(x)));
err = trigrat_aux(t,arg,next);
if(err)
return 1;
strcpy(reason, english(755)); /* mult num and denom by */
strcat(reason, " ");
strcat(reason, "1 - sin x");
return 0;
}
/*__________________________________________________________________*/
int trigrationalizedenom3(term t, term arg, term *next, char *reason)
/* multiply num and denom by cos x+sin x */
/* Works on an integral with a fraction for an integrand,
or directly on a fraction in menu mode or term selection mode
*/
{ term x;
int err;
if(FUNCTOR(t) != INTEGRAL)
return 1;
x = ARG(1,t);
arg = sum(sin1(x),cos1(x));
err = trigrat_aux(t,arg,next);
if(err)
return 1;
strcpy(reason, english(755)); /* mult num and denom by */
strcat(reason, " ");
strcat(reason, "sin x + cos x");
return 0;
}
/*__________________________________________________________________*/
int trigrationalizedenom6(term t, term arg, term *next, char *reason)
/* multiply num and denom by cos x-sin x */
/* Works on an integral with a fraction for an integrand,
or directly on a fraction in menu mode or term selection mode
*/
{ term x;
int err;
if(FUNCTOR(t) != INTEGRAL)
return 1;
x = ARG(1,t);
arg = sum(cos1(x),tnegate(sin1(x)));
err = trigrat_aux(t,arg,next);
if(err)
return 1;
strcpy(reason, english(755)); /* mult num and denom by */
strcat(reason, " ");
strcat(reason, "cos x - sin x");
return 0;
}
/*_________________________________________________________________*/
int adddegrees(term t, term arg, term *next, char *reason)
/* a\\deg + b\\deg = (a+b)\\deg */
{ int err;
if(FUNCTOR(t) != '+')
return 1;
err = degree_simp(t,next);
if(err)
return 1;
strcpy(reason,"$a\\deg + b\\deg = (a+b)\\deg $");
HIGHLIGHT(*next);
return 0;
}
/*_________________________________________________________________*/
int multdegrees(term t, term arg, term *next, char *reason)
/* ca\\deg = (ca)\\deg */
{ int err;
if(FUNCTOR(t) != '*')
return 1;
err = degree_simp(t,next);
if(err)
return 1;
strcpy(reason,"$ca\\deg = (ca)\\deg $");
HIGHLIGHT(*next);
return 0;
}
/*_________________________________________________________________*/
int divdegrees(term t, term arg, term *next, char *reason)
/* a\\deg /c = (a/c)\\deg */
{ int err;
if(FUNCTOR(t) != '*')
return 1;
err = degree_simp(t,next);
if(err)
return 1;
strcpy(reason,"$a\\deg /c = (a/c)\\deg $");
HIGHLIGHT(*next);
return 0;
}
/*__________________________________________________________________*/
int sinsqeven(term t, term arg, term *next, char *reason)
/* sin^2(-u) = sin^2 u */
{ return sqeven(SIN, t,next,reason);
}
/*__________________________________________________________________*/
int cossqeven(term t, term arg, term *next, char *reason)
/* cos^2(-u) = cos^2 u */
{ return sqeven(COS, t,next,reason);
}
/*__________________________________________________________________*/
int tansqeven(term t, term arg, term *next, char *reason)
/* tan^2(-u) = tan^2 u */
{ return sqeven(TAN, t,next,reason);
}
/*__________________________________________________________________*/
int cotsqeven(term t, term arg, term *next, char *reason)
/* cot^2(-u) = cot^2 u */
{ return sqeven(COT, t,next,reason);
}
/*__________________________________________________________________*/
int secsqeven(term t, term arg, term *next, char *reason)
/* sec^2(-u) = sec^2 u */
{ return sqeven(SEC, t,next,reason);
}
/*__________________________________________________________________*/
int cscsqeven(term t, term arg, term *next, char *reason)
/* csc^2(-u) = csc^2 u */
{ return sqeven(CSC, t,next,reason);
}
/*__________________________________________________________________*/
static int sqeven(unsigned short f, term t, term *next, char *reason)
/* f^2(-u) = f^2 u for trig functions f */
{ term u,v,p,q;
int err;
if(FUNCTOR(t) != '^')
return 1;
if(!TRIGFUNCTOR(f))
return 1;
if(!NEGATIVE(ARG(0,ARG(0,t))))
return 1;
if(ISINTEGER(ARG(1,t)) && ISODD(ARG(1,t)))
return 1;
if(!ISINTEGER(ARG(1,t)))
{ err = cancel(ARG(1,t),two,&p,&q);
if(err)
return 1;
err = infer(type(q,INTEGER));
if(err)
return 1;
}
u = ARG(0,ARG(0,ARG(0,t)));
v = make_term(f,1);
ARGREP(v,0,u);
*next = make_power(v,ARG(1,t));
switch(f)
{ case SIN:
strcpy(reason, "$sin^2(-u) = sin^2 u$");
break;
case COS:
strcpy(reason, "$cos^2(-u) = cos^2 u$");
break;
case TAN:
strcpy(reason, "$tan^2(-u) = tan^2 u$");
break;
case COT:
strcpy(reason, "$cot^2(-u) = cot^2 u$");
break;
case SEC:
strcpy(reason, "$sec^2(-u) = sec^2 u$");
break;
case CSC:
strcpy(reason, "$csc^2(-u) = csc^2 u$");
break;
}
HIGHLIGHT(*next);
return 0;
}
/*__________________________________________________________________*/
int trigsuminfraction(term t, term arg, term *next, char *reason)
/* apply difofcos, sumofcos, difofsin, sumofsin to the numerator
of a fraction if one of these four (not necessarily the same one)
will apply to both num and denom.
*/
{ term num,denom,a[4];
int i,err,sign[4];
unsigned short f;
unsigned short path[3];
term temp;
if(!FRACTION(t))
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(num) != '+' || ARITY(num) != 2)
return 1;
if(FUNCTOR(denom) != '+' || ARITY(denom) != 2)
return 1;
a[0] = ARG(0,num);
a[1] = ARG(1,num);
a[2] = ARG(0,denom);
a[3] = ARG(1,denom);
for(i=0;i<4;i++)
{ if(NEGATIVE(a[i]))
{ a[i] = ARG(0,a[i]);
sign[i] = 1;
}
else
sign[i] = 0;
f = FUNCTOR(a[i]);
if(f != SIN && f != COS)
return 1;
}
if(sign[2] != sign[3])
{ err = difofsin(denom,arg,&temp,reason);
if(err)
{ err = difofcos(denom,arg,&temp,reason);
if(err)
return 1;
}
}
else
{ err = sumofsin(denom,arg,&temp,reason);
if(err)
{ err = sumofcos(denom,arg,&temp,reason);
if(err)
return 1;
}
}
/* So it works in the denom */
if(sign[0] != sign[1])
{ err = difofsin(num,arg,&temp,reason);
if(err)
{ err = difofcos(num,arg,&temp,reason);
if(err)
return 1;
SetShowStepOperation(difofcos);
}
else
SetShowStepOperation(difofsin);
}
else
{ err = sumofsin(num,arg,&temp,reason);
if(err)
{ err = sumofcos(num,arg,&temp,reason);
if(err)
return 1;
SetShowStepOperation(sumofcos);
}
else
SetShowStepOperation(sumofsin);
}
/* It works in both num and denom. Apply it only in num */
HIGHLIGHT(temp);
*next = make_fraction(temp,denom);
path[0] = '/';
path[1] = 1; /* numerator */
path[2] = 0;
set_pathtail(path);
return 0;
}
/*______________________________________________________________________*/
static term trigsimp(term t)
/* use the laws sin(-x) = -sin x etc. on subterms of t and
return the result. */
{ unsigned short n,f;
term u,ans;
int i;
if(ATOMIC(t))
return t;
n = ARITY(t);
f = FUNCTOR(t);
if(TRIGFUNCTOR(f) && NEGATIVE(ARG(0,t)))
{ u = ARG(0,ARG(0,t));
switch(f)
{ case SIN:
return tnegate(sin1(u));
case COS:
return cos1(u);
case TAN:
return tnegate(tan1(u));
case COT:
return tnegate(cot1(u));
case SEC:
return sec1(u);
case CSC:
return tnegate(csc1(u));
}
}
if(TRIGFUNCTOR(f) && FUNCTOR(ARG(0,t)) == DEG && NEGATIVE(ARG(0,ARG(0,t))))
{ u = deg1(ARG(0,ARG(0,ARG(0,t))));
switch(f)
{ case SIN:
return tnegate(sin1(u));
case COS:
return cos1(u);
case TAN:
return tnegate(tan1(u));
case COT:
return tnegate(cot1(u));
case SEC:
return sec1(u);
case CSC:
return tnegate(csc1(u));
}
}
ans = make_term(f,n);
for(i=0;i<n;i++)
ARGREP(ans,i,trigsimp(ARG(i,t)));
return ans;
}
/*_________________________________________________________________*/
static void adjust_polyvalfunctionflag( term t)
/* if t is a product or negation of a product
containing a trig function with seminumerical
argument as a factor, call set_polyvalfunctionflag(0).
*/
{ unsigned short n,f;
int i;
term u,v;
if(NEGATIVE(t))
t = ARG(0,t);
if(FUNCTOR(t) != '*')
return;
n = ARITY(t);
for(i=0;i<n;i++)
{ u = ARG(i,t);
f = FUNCTOR(u);
polyval(ARG(0,u),&v);
if(TRIGFUNCTOR(f) && seminumerical(v))
{ set_polyvalfunctionflag(0);
return;
}
}
}
/*________________________________________________________________*/
int periodicform(term t, term arg, term *next, char *reason)
/* Put solution in periodic form */
/* t must be a solved equation or an OR of solved equations.
The solution must also contain an existential integer parameter n.
If the original equation (that is, the first one involving the
current eigenvariable) is periodic with period p, then put the
solutions into the form c + np where c does not contain n.
For example, if t is x = pi_term/3 + 2n pi_term, but the period of the original
equation is 4 pi_term, *next will be returned as
or(x = pi_term/3 + 4n pi_term, x = 4pi/3 + 4n pi_term)
This should not work in auto mode if the new period is a divisor of
the old one, e.g. if the original equation involved only cot and tan and
so has period pi_term, but the solutions come out with ...+2k pi.
*/
{ int i,err,nextdefn,linenumber;
term x,ans,test,period;
defn d;
x = get_eigenvariable();
/* Locate the original equation */
nextdefn = get_nextdefn();
for(i=nextdefn-1;i>=0;--i)
{ d = get_defn(i);
if(equals(d.left,x))
{ linenumber = d.line;
break;
}
}
if(i < 0)
linenumber = 0;
test = history(linenumber);
/* but 'test' may still not be the desired equation, it might be
an OR of several equations, one of which is the desired one.
For this to work, all the equations in 'test' which contain x
must be periodic in x with a common period. */
err = periodic_in(test,x,&period);
if(err)
{ errbuf(0,english(1658));
/* Original equation is not periodic */
return 1;
}
if(!solved(t,x))
{ errbuf(0,english(1657)); /* Equations must first be solved. */
return 1;
}
err = period_aux(t,x,period,&ans,next);
if(err == 2)
{ errbuf(0,english(1659));
/* Solution does not contain an integer parameter. */
return 1;
}
if(err)
return 1;
if(equals(t,*next))
return 1;
strcpy(reason, english(1660)); /* periodic form */
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________*/
static int multipleofpi(term a)
/* return 1 if a is an integer multiple of pi */
{ term p;
polyval(make_fraction(a,pi_term),&p);
return isinteger(p);
}
/*________________________________________________________________*/
static int odd_multiple_of_piover2(term a)
/* return 1 if a is an odd multiple of pi/2 */
{ term p;
polyval(make_fraction(product(two,a),pi_term),&p);
return isinteger(p) && isodd(p);
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists