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.
*/
#define ALGEBRA_DLL
#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 "document.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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int doublecos5(term t, term arg, term *next, char *reason)
/* cos 2� + 1 = 2cos^2 � */
{ 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� + 1 = 2cos^2 �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int doublecos6(term t, term arg, term *next, char *reason)
/* cos 2� - 1 = - 2 sin^2 � */
{ 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� - 1 = -2sin^2 �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int doublecos4(term t, term arg, term *next, char *reason)
/* cos 2� = cos^2 � - sin^2 � (must be tried last in auto mode)*/
/* associated to '+' for use when cos 2� 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� */
{ 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� 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�=cos^2 � -sin^2 �$");
return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA 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 = check(nonzero(tan1(x)));
if(err)
{ err = check(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 = check(nonzero(tan1(x)));
if(err)
{ err = check(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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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 = check(nonzero(cot1(x)));
if(err)
{ err = check(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 = check(nonzero(cot1(x)));
if(err)
{ err = check(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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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� x,x) */
{ int err = recip_aux(COS,SEC,t,next);
if(err)
return 1;
strcpy(reason,"1 / cos x = sec x");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int costosin(term t, term arg, term *next, char *reason)
/* cos(�/2-�) = sin � */
{ 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(�/2-�) = sin �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sintocos(term t, term arg, term *next, char *reason)
/* sin(�/2-�) = cos � */
{ 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(�/2-�) = cos �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tantocot(term t, term arg, term *next, char *reason)
/* tan(�/2-�) = cot � */
{ 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(�/2-�) = cot �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cotcomplement(term t, term arg, term *next, char *reason)
/* cot(�/2-�) = tan � */
{ 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(�/2-�) = tan �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int seccomplement(term t, term arg, term *next, char *reason)
/* sec(�/2-�) = csc � */
{ 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(�/2-�) = csc �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int csccomplement(term t, term arg, term *next, char *reason)
/* csc(�/2-�) = sec � */
{ 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(�/2-�) = sec �$");
return 0;
}
/*__________________________________________________________________*/
#define NINETYDEGREES(x) (FUNCTOR(x) == DEG && ISINTEGER(ARG(0,x)) && INTDATA(ARG(0,x)) == 90)
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int costosindeg(term t, term arg, term *next, char *reason)
/* cos(90�-�) = sin � */
{ 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�-�) = sin �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sintocosdeg(term t, term arg, term *next, char *reason)
/* sin(90�-�) = cos � */
{ 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�-�) = cos �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tantocotdeg(term t, term arg, term *next, char *reason)
/* tan(90�-�) = cot � */
{ 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�-�) = cot �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cotcomplementdeg(term t, term arg, term *next, char *reason)
/* cot(90�-�) = tan � */
{ 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�-�) = tan �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int seccomplementdeg(term t, term arg, term *next, char *reason)
/* sec(90�-�) = csc � */
{ 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�-�) = csc �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int csccomplementdeg(term t, term arg, term *next, char *reason)
/* csc(90�-�) = sec � */
{ 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�-�) = sec �$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sincos(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 = $�[sin(x+y)+sin(x-y)]$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cossin(term t, term arg, term *next, char *reason)
/* cos x sin y = �[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 = $�[sin(x+y)-sin(x-y)]$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublesin(term t, term arg, term *next, char *reason)
/* cos x sin x = � 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� */
if(err == 1)
*next = u;
if(FUNCTOR(*next) == '*' && ONE(ARG(0,*next)))
/* Don't produce 1 sin 2� */
{ 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 � sin � = � sin 2�$");
else
strcpy(reason,"$2cos � sin � = sin 2�$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublesin2(term t, term arg, term *next, char *reason)
/* 2 cos x sin x = sin 2x */
{ return reversedoublesin(t,arg,next,reason);
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsin(term t, term arg, term *next, char *reason)
/* sin x sin y = �[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 = $�[cos(x-y)-cos(x+y)]$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int coscos(term t, term arg, term *next, char *reason)
/* cos x cos y = �[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 = $�[cos(x+y)+cos(x-y)]$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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,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 = 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sumofsin(term t, term arg, term *next, char *reason)
/* sin x + sin y = 2 sin �(x+y) cos �(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�(x+y) cos�(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. */
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int difofsin(term t, term arg, term *next, char *reason)
/* sin x - sin y = 2 sin �(x-y) cos �(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�(x-y) cos�(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));
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sumofcos(term t, term arg, term *next, char *reason)
/* cos x + cos y = 2 cos �(x+y) cos �(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�(x+y) cos�(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));
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int difofcos(term t, term arg, term *next, char *reason)
/* cos x - cos y = -2 sin �(x+y) sin �(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�(x+y) sin�(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 */
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sintocos2(term t, term arg, term *next, char *reason)
/* sin � = cos(�/2-�) */
/* 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,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 � = cos(�/2-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int costosin2(term t, term arg, term *next, char *reason)
/* cos � = sin(�/2-�) */
/* 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,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 � = sin(�/2-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tantocot2(term t, term arg, term *next, char *reason)
/* tan � = cot(�/2-�) */
/* 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,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 � = cot(�/2-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cottotan2(term t, term arg, term *next, char *reason)
/* cot � = tan(�/2-�) */
/* 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,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 � = tan(�/2-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sectocsc2(term t, term arg, term *next, char *reason)
/* sec � = csc(�/2-�) */
/* 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,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 � = csc(�/2-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int csctosec2(term t, term arg, term *next, char *reason)
/* csc � = sec(�/2-�) */
/* 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,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 � = sec(�/2-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sintocos2deg(term t, term arg, term *next, char *reason)
/* sin � = cos(90�-�) */
/* 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 � = cos(90�-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int costosin2deg(term t, term arg, term *next, char *reason)
/* cos � = sin(90�-�) */
/* 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 � = sin(90�-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tantocot2deg(term t, term arg, term *next, char *reason)
/* tan � = cot(90�-�) */
/* 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 � = cot(90�-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cottotan2deg(term t, term arg, term *next, char *reason)
/* cot � = tan(90�-�) */
/* 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 � = tan(90�-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sectocsc2deg(term t, term arg, term *next, char *reason)
/* sec � = csc(90�-�) */
/* 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 � = csc(90�-�)$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int csctosec2deg(term t, term arg, term *next, char *reason)
/* csc � = sec(90�-�) */
/* 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 � = sec(90�-�)$");
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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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, "1 + cos x");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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, "1 - cos x");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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, "1 + sin x");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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, "1 - sin x");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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, "sin x + cos x");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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, "cos x - sin x");
return 0;
}
/*_________________________________________________________________*/
MEXPORT_ALGEBRA int adddegrees(term t, term arg, term *next, char *reason)
/* a� + b� = (a+b)� */
{ int err;
if(FUNCTOR(t) != '+')
return 1;
err = degree_simp(t,next);
if(err)
return 1;
strcpy(reason,"$a� + b� = (a+b)�$");
HIGHLIGHT(*next);
return 0;
}
/*_________________________________________________________________*/
MEXPORT_ALGEBRA int multdegrees(term t, term arg, term *next, char *reason)
/* ca� = (ca)� */
{ int err;
if(FUNCTOR(t) != '*')
return 1;
err = degree_simp(t,next);
if(err)
return 1;
strcpy(reason,"$ca� = (ca)�$");
HIGHLIGHT(*next);
return 0;
}
/*_________________________________________________________________*/
MEXPORT_ALGEBRA int divdegrees(term t, term arg, term *next, char *reason)
/* a�/c = (a/c)�*/
{ int err;
if(FUNCTOR(t) != '*')
return 1;
err = degree_simp(t,next);
if(err)
return 1;
strcpy(reason,"$a�/c = (a/c)�$");
HIGHLIGHT(*next);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsqeven(term t, term arg, term *next, char *reason)
/* sin^2(-u) = sin^2 u */
{ return sqeven(SIN, t,next,reason);
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cossqeven(term t, term arg, term *next, char *reason)
/* cos^2(-u) = cos^2 u */
{ return sqeven(COS, t,next,reason);
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tansqeven(term t, term arg, term *next, char *reason)
/* tan^2(-u) = tan^2 u */
{ return sqeven(TAN, t,next,reason);
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cotsqeven(term t, term arg, term *next, char *reason)
/* cot^2(-u) = cot^2 u */
{ return sqeven(COT, t,next,reason);
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int secsqeven(term t, term arg, term *next, char *reason)
/* sec^2(-u) = sec^2 u */
{ return sqeven(SEC, t,next,reason);
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA 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;
}
}
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA 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/3 + 2n pi, but the period of the original
equation is 4 pi, *next will be returned as
or(x = pi/3 + 4n pi, x = 4pi/3 + 4n pi)
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, 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),&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),&p);
return isinteger(p) && isodd(p);
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists