Sindbad~EG File Manager
/* trig_squares, trig_sum operators
M. Beeson, for MathXpert
1.13.91 original date
5.12.98 last modified
*/
#define ALGEBRA_DLL
#include <string.h>
#include "globals.h"
#include "ops.h"
#include "trig.h"
#include "match.h"
#include "order.h"
#include "cancel.h"
#include "prover.h"
#include "trigsq.h"
#include "symbols.h"
#include "calc.h"
#include "errbuf.h"
#include "pvalaux.h" /* isinteger */
#include "pathtail.h" /* set_pathtail, pathncopy, etc */
#include "autosimp.h" /* SetShowStepOperation */
#include "tdefn.h"
#include "cflags.h"
static void check_periodic(term t);
static void check_complementary(term t);
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsquare1(term t, term arg, term *next, char *reason)
/* sin^2 a + cos^2 a = 1 */
{ term lhs,a,b,c,temp,u,v;
int i,j,k,err;
unsigned short n;
unsigned short path[5];
if(FUNCTOR(t) != '+')
return 1;
lhs = sum(make_power(sin1(var0),two),make_power(cos1(var0),two));
err = match(t,lhs,one,&a,next); /* instantiate a and *next */
if(!err)
{ HIGHLIGHT(*next);
strcpy(reason,"$sin^2 a + cos^2 a = 1$");
return 0;
}
/* But don't give up; work on x sin^2 x + x cos ^2 x too */
n = ARITY(t);
for(i=0;i<n;i++)
{ if(!contains(ARG(i,t),SIN))
continue;
for(j=0;j<n;j++)
{ if(j == i || !contains(ARG(j,t),COS))
continue;
u = sum(ARG(i,t),ARG(j,t));
if(!content_factor(u,&c,&b) &&
!match(b,lhs,one,&a,&temp)
)
{ if(j == i+1 && get_mathmode() == AUTOMODE)
{ /* imitate content-factoring for ShowStep */
SetShowStepOperation(contentfactor);
if(n == 2)
{ *next = product(c,b);
HIGHLIGHT(*next);
strcpy(reason, "ab+ac = a(b+c)");
return 0;
}
*next= make_term('+',(unsigned short)(n-1));
for(k=0;k<n-1;k++)
{ if(k==i)
{ ARGREP(*next,k, product(c,b));
HIGHLIGHT(ARG(k,*next));
}
else if(k<i)
ARGREP(*next,k,ARG(k,t));
else
ARGREP(*next,k,ARG(k+1,t));
}
path[0] = '+';
path[1] = i+1;
path[2] = SUBRANGE;
path[3] = j+1;
path[4] = 0;
set_pathtail(path);
strcpy(reason, "ab+ac = a(b+c)");
return 0;
}
v = NEGATIVE(temp) ?
tnegate(product(c,ARG(0,temp))) :
NEGATIVE(c) ?
product(ARG(0,c),temp) :
product(c,temp);
if(n == 2)
{ *next = v;
HIGHLIGHT(*next);
strcpy(reason,"$sin^2 a + cos^2 a = 1$");
return 0;
}
*next = make_term('+',(unsigned short)(n-1));
if(j < i)
{ k=i;
i=j;
j=k;
}
for(k=0;k<n-1;k++)
ARGREP(*next,k,k<i ? ARG(k,t) : k == i ? v : k < j ? ARG(k,t) : ARG(k+1,t));
HIGHLIGHT(ARG(i,*next));
strcpy(reason,"$sin^2 a + cos^2 a = 1$");
return 0;
}
}
}
destroy_term(lhs);
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsquare2(term t, term arg, term *next, char *reason)
/* 1 - sin^2 a = cos^2 a */
{ term lhs,rhs,a;
unsigned short path[11];
int i,j;
int err;
if(FRACTION(t) && get_mathmode() == AUTOMODE)
{ term x;
int whicharg;
term newnum,newdenom;;
err = sq_aux(ARG(1,t),COS,&x,&whicharg);
if(!err)
{ err = sinsquare2(ARG(0,t),arg,&newnum,reason);
if(err)
return 1;
*next = make_fraction(newnum,ARG(1,t));
path[0] = '/';
path[1] = 1;
path[2] = 0;
if(FUNCTOR(ARG(0,t))=='^' || FUNCTOR(ARG(0,t)) == '*')
pathcat(path,get_pathtail());
set_pathtail(path);
goto out;
}
err = sq_aux(ARG(0,t),COS,&x,&whicharg);
if(!err)
{ err = sinsquare2(ARG(1,t),arg,&newdenom,reason);
if(err)
return 1;
*next = make_fraction(ARG(0,t),newdenom);;
path[0] = '/';
path[1] = 2;
path[2] = 0;
if(FUNCTOR(ARG(1,t))== '^' || FUNCTOR(ARG(1,t)) == '*')
pathcat(path,get_pathtail());
set_pathtail(path);
goto out;
}
return 1;
}
if(FUNCTOR(t) == '^' && get_mathmode() == AUTOMODE)
{ term temp;
if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
return 1;
err = sinsquare2(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = make_power(temp,ARG(1,t));
path[0] = '^';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
goto out;
}
if(FUNCTOR(t) == '*' && get_mathmode() == AUTOMODE)
{ unsigned short n = ARITY(t);
term u,temp;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) != '^' && FUNCTOR(u) != '+')
continue;
err = sinsquare2(u,arg,&temp,reason);
if(!err)
{ path[0] = '*';
path[1] = i+1;
path[2] = 0;
if(FUNCTOR(u) == '^')
pathcat(path, get_pathtail());
set_pathtail(path);
break;
}
}
if(i==n)
return 1;
*next = make_term('*',n);
for(j=0;j<n;j++)
ARGREP(*next,j,i==j ? temp : ARG(j,t));
goto out;
}
lhs = sum(one,tnegate(make_power(sin1(var0),two)));
rhs = 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,"$1 - sin^2 a = cos^2 a$");
out:
release(cancelop); /* perhaps inhibited by trigrationalizedenom1 or trigrationalizedenom2 */
release(polyvalop);
release(cancelgcd);
release(differenceofsquares);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsquare3(term t, term arg, term *next, char *reason)
/* 1 - cos^2 a = sin^2 a */
{ term lhs,rhs,a;
int err,i,j;
unsigned short path[11];
if(FRACTION(t) && get_mathmode() == AUTOMODE)
{ term x;
int whicharg;
term newnum,newdenom;;
err = sq_aux(ARG(1,t),SIN,&x,&whicharg);
if(!err)
{ err = sinsquare3(ARG(0,t),arg,&newnum,reason);
if(err)
return 1;
*next = make_fraction(newnum,ARG(1,t));
path[0] = '/';
path[1] = 1;
path[2] = 0;
if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
pathcat(path, get_pathtail());
set_pathtail(path);
goto out;
}
err = sq_aux(ARG(0,t),SIN,&x,&whicharg);
if(!err)
{ err = sinsquare3(ARG(1,t),arg,&newdenom,reason);
if(err)
return 1;
*next = make_fraction(ARG(0,t),newdenom);
path[0] = '/';
path[1] = 2;
path[2] = 0;
if(FUNCTOR(ARG(1,t)) == '^' || FUNCTOR(ARG(1,t)) == '*')
pathcat(path,get_pathtail());
set_pathtail(path);
goto out;
}
return 1;
}
if(FUNCTOR(t) == '^' && get_mathmode() == AUTOMODE)
{ term temp;
if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
return 1;
err = sinsquare3(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = make_power(temp,ARG(1,t));
path[0] = '^';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
goto out;
}
if(FUNCTOR(t) == '*' && get_mathmode() == AUTOMODE)
{ unsigned short n = ARITY(t);
term u,temp;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) != '^' && FUNCTOR(u) != '+')
continue;
err = sinsquare3(u,arg,&temp,reason);
if(!err)
{ path[0] = '*';
path[1] = i+1;
path[2] = 0;
if(FUNCTOR(u) == '^')
pathcat(path, get_pathtail());
set_pathtail(path);
break;
}
}
if(i==n)
return 1;
*next = make_term('*',n);
for(j=0;j<n;j++)
ARGREP(*next,j,i==j ? temp : ARG(j,t));
goto out;
}
lhs = sum(one,tnegate(make_power(cos1(var0),two)));
rhs = make_power(sin1(var0),two);
err = match(t,lhs,rhs,&a,next); /* instantiate a and *next */
if(err)
{ destroy_term(lhs);
return 1;
}
HIGHLIGHT(*next);
strcpy(reason,"$1 - cos^2 a = sin^2 a$");
out:
release(cancelop); /* perhaps inhibited by trigrationalizedenom1 or trigrationalizedenom2 */
release(polyvalop);
release(cancelgcd);
release(differenceofsquares);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int secsqminustansq(term t, term arg, term *next, char *reason)
/* sec^2 a - tan^2 a = 1 */
{ term lhs,rhs,a;
int err;
lhs = sum(make_power(sec1(var0),two),tnegate(make_power(tan1(var0),two)));
rhs = one;
err = match(t,lhs,rhs,&a,next); /* instantiate a and *next */
if(err)
{ destroy_term(lhs);
return 1;
}
HIGHLIGHT(*next);
strcpy(reason,"$sec^2 a - tan^2 a = 1$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tansquare1(term t, term arg, term *next, char *reason)
/* tan^2 a + 1 = sec^2 a */
{ term lhs,rhs,a;
int err;
lhs = sum(make_power(tan1(var0),two),one);
rhs = make_power(sec1(var0),two);
err = match(t,lhs,rhs,&a,next); /* instantiate a and *next */
if(err)
{ destroy_term(lhs);
return 1;
}
HIGHLIGHT(*next);
strcpy(reason,"$tan^2 a + 1 = sec^2 a$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tansquare2(term t, term arg, term *next, char *reason)
/* sec^2 a - 1 = tan^2 a */
{ term lhs,rhs,a;
int err;
unsigned short path[11];
if(FRACTION(t) && get_mathmode() == AUTOMODE)
{ term x;
int whicharg;
term newnum,newdenom;;
err = sq_aux(ARG(1,t),TAN,&x,&whicharg);
if(!err)
{ err = tansquare2(ARG(0,t),arg,&newnum,reason);
if(err)
return 1;
*next = make_fraction(newnum,ARG(1,t));
path[0] = '/';
path[1] = 1;
path[2] = 0;
if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
pathcat(path,get_pathtail());
set_pathtail(path);
return 0;
}
err = sq_aux(ARG(0,t),TAN,&x,&whicharg);
if(!err)
{ err = tansquare2(ARG(1,t),arg,&newdenom,reason);
if(err)
return 1;
*next = make_fraction(ARG(0,t),newdenom);
path[0] = '/';
path[1] = 2;
path[2] = 0;
if(FUNCTOR(ARG(1,t)) == '^' || FUNCTOR(ARG(1,t)) == '*')
pathcat(path, get_pathtail());
set_pathtail(path);
return 0;
}
return 1;
}
if(FUNCTOR(t) == '^' && get_mathmode() == AUTOMODE)
{ term temp;
if(FUNCTOR(ARG(0,t)) == '^' || FUNCTOR(ARG(0,t)) == '*')
return 1;
err = tansquare2(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = make_power(temp,ARG(1,t));
path[0] = '^';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
return 0;
}
if(FUNCTOR(t) == '*' && get_mathmode() == AUTOMODE)
{ int i,j;
unsigned short n = ARITY(t);
term u,temp;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) != '^' && FUNCTOR(u) != '+')
continue;
err = tansquare2(u,arg,&temp,reason);
if(!err)
{ path[0] = '*';
path[1] = i+1;
path[2] = 0;
if(FUNCTOR(u) == '^')
pathcat(path, get_pathtail());
break;
}
}
if(i==n)
return 1;
*next = make_term('*',n);
for(j=0;j<n;j++)
ARGREP(*next,j,i==j ? temp : ARG(j,t));
return 0;
}
lhs = sum(make_power(sec1(var0),two),minusone);
rhs = make_power(tan1(var0),two);
err = match(t,lhs,rhs,&a,next); /* instantiate a and *next */
if(err)
{ destroy_term(lhs);
return 1;
}
HIGHLIGHT(*next);
strcpy(reason,"$sec^2 a - 1 = tan^2 a$");
return 0;
}
/*___________________________________________________________*/
int sq_aux(term u, unsigned short f, term *x, int *whicharg)
/* Does u equal f^2(...) or contain it as a
factor? if so instantiate *x to ... and return 0. If not return 1.
If u is a product, return in *whicharg the index of the arg which
was found to contain f^2. Otherwise *whicharg is garbage. */
{ unsigned short n;
int i;
term v;
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == f && equals(ARG(1,u),two))
{ *x = ARG(0,ARG(0,u));
return 0;
}
if(FUNCTOR(u) != '*')
return 1;
n = ARITY(u);
for(i=0;i<n;i++)
{ v = ARG(i,u);
if(FUNCTOR(v) == '^' && FUNCTOR(ARG(0,v)) == f && equals(ARG(1,v),two))
{ *x = ARG(0,ARG(0,v));
*whicharg = i;
return 0;
}
}
return 1;
}
/*___________________________________________________________*/
static int sq_aux2(term u, term x, unsigned short g)
/* does 1-g(x) or 1+g(x) occur as u or as a factor of u?
Or 1-g^2(x), or g^2x -1?
Or g(x) � 1? Or a power of any of those things?
If so return 0, if not return 1. */
{ term v,w;
unsigned short n;
int i,err;
if(FUNCTOR(u) == '+' && ARITY(u)==2)
{ v = ARG(0,u);
w = ARG(1,u);
if(NEGATIVE(v))
v = ARG(0,v);
if(NEGATIVE(w))
w = ARG(0,w);
if(FUNCTOR(v) == g && ONE(w))
return 0;
if(FUNCTOR(w) == g && ONE(v))
return 0;
return 1;
}
if(FUNCTOR(u) == '^')
return sq_aux2(ARG(0,u),x,g);
if(FUNCTOR(u) != '*')
return 1;
n = ARITY(u);
for(i=0;i<n;i++)
{ err = sq_aux2(ARG(i,u),x,g);
if(!err)
return 0;
}
return 1;
}
/*___________________________________________________________*/
int sqinfract(term t, unsigned short f, term *next, char *reason)
/* f is COS,SIN, TAN,or COT; t is a fraction.
Use cossqtosinsq (if f==COS)
sinsqtocossq (if f == SIN)
cotsqtocscsq (if f == COT)
tansqtoseqsq (if f == TAN)
on the numerator or denom of t, if a cancellation
will later be possible. Example: (1-sin x)/cos^2 x.
Another example: (1-sin x)^2/cos^2 x. */
{ term num = ARG(0,t);
term denom = ARG(1,t);
term x,temp,newnum,newdenom;
int i,j,err;
actualop op;
unsigned short path[5];
unsigned h = f==SIN ? COS : f == TAN ? SEC : f == COT ? CSC : SIN;
unsigned short g = (unsigned short) h;
/* comments will suppose f == SIN for simplicity, so g == COS */
err = sq_aux(denom,f,&x,&i); /* does cos^2 occur there? */
if(err)
{ err = sq_aux(num,f,&x,&i);
if(err)
return 1;
err = sq_aux2(denom,x,g); /* does 1-sin x or 1+sin x occur? */
/* or a power of it? */
if(err)
return 1;
if(FUNCTOR(num) == '*')
{ switch(f)
{ case COS:
op = cossqtosinsq;
break;
case SIN:
op = sinsqtocossq;
break;
case COT:
op = cotsqtocscsq;
break;
case TAN:
op = tansqtosecsq;
break;
default:
return 1;
}
err = (*op)(ARG(i,num),zero,&temp,reason);
if(err)
return 1;
path[0] = '/';
path[1] = 1;
path[2] = '*';
path[3] = (unsigned short)(i+1);
path[4] = 0;
set_pathtail(path);
SetShowStepOperation(op);
newnum = make_term('*',ARITY(num));
for(j=0;j<ARITY(num);j++)
ARGREP(newnum,j,j==i ? temp : ARG(j,num));
}
else
{ switch(f)
{ case COS:
op = cossqtosinsq;
break;
case SIN:
op = sinsqtocossq;
break;
case COT:
op = cotsqtocscsq;
break;
case TAN:
op = tansqtosecsq;
break;
default:
return 1;
}
err = (*op)(num,zero,&newnum,reason);
if(err)
return 1;
path[0] = '/';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
SetShowStepOperation(op);
}
*next = make_fraction(newnum,denom);
return 0;
}
err = sq_aux2(num,x,g); /* does 1-sin x or 1+sin x occur? */
if(err)
return 1;
if(FUNCTOR(denom) == '*')
{ switch(f)
{ case COS:
op = cossqtosinsq;
break;
case SIN:
op = sinsqtocossq;
break;
case COT:
op = cotsqtocscsq;
break;
case TAN:
op = tansqtosecsq;
break;
default:
return 1;
}
err = (*op)(ARG(i,denom),zero,&temp,reason);
if(err)
return 1;
newdenom = make_term('*',ARITY(denom));
path[0] = '/';
path[1] = 2;
path[2] = '*';
path[3] = (unsigned short) (i+1);
path[4] = 0;
set_pathtail(path);
SetShowStepOperation(op);
for(j=0;j<ARITY(denom);j++)
ARGREP(newdenom,j,j==i ? temp : ARG(j,denom));
}
else
{ switch(f)
{ case COS:
op = cossqtosinsq;
break;
case SIN:
op = sinsqtocossq;
break;
case COT:
op = cotsqtocscsq;
break;
case TAN:
op = tansqtosecsq;
break;
default:
return 1;
}
err = (*op)(denom,zero,&newdenom,reason);
if(err)
return 1;
path[0] = '/';
path[1] = 2;
path[2] = 0;
set_pathtail(path);
SetShowStepOperation(op);
}
*next = make_fraction(num,newdenom);
release(cancelgcd); /* in case inhibited by trigrationalize1 etc. */
return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int cossqtosinsq(term t, term arg, term *next, char *reason)
/* cos^2 u = 1 - sin^2 u. But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
It also works on a quotient, for example (1-sin x)/cos^2 x, if a
cancellation will be possible later.
*/
{ term u,v,temp,c,s;
int i,j,err;
int powerflag;
unsigned short n;
unsigned short path[11];
int success = 0;
if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
return sqinfract(t,COS,next,reason);
if(FUNCTOR(t) == '=')
{ if(FUNCTOR(ARG(0,t)) == '^' &&
FUNCTOR(ARG(0,ARG(0,t))) == COS &&
iseven(ARG(1,ARG(0,t)))
)
{ err = cossqtosinsq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(temp,ARG(1,t));
path[0] = '=';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
return 0;
}
else if(FUNCTOR(ARG(1,t)) == '^' &&
FUNCTOR(ARG(0,ARG(1,t))) == COS &&
iseven(ARG(1,ARG(1,t)))
)
{ err = cossqtosinsq(ARG(1,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(ARG(0,t),temp);
path[0] = '=';
path[1] = 2;
path[2] = 0;
set_pathtail(path);
return 0;
}
}
if(FUNCTOR(t)== '+' && contains(t,COS))
{ n = ARITY(t);
v = make_term('+',n);
powerflag = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
err = cossqtosinsq(u,arg,&temp,reason);
if(!err)
{ ARGREP(v,i,temp);
success = 1;
path[0] = '+';
path[1] = i+1;
path[2] = 0;
if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
pathcat(path,get_pathtail());
set_pathtail(path);
/* Now set powerflag if we don't want to call polyval on the result
because that will produce a too-large step for a student */
temp = NEGATIVE(u) ? ARG(0,u) : u;
if(FUNCTOR(temp) == '*')
{ ratpart2(temp,&c,&s);
temp = s;
}
if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
powerflag = 1;
if(FUNCTOR(temp) == '*')
powerflag = 1;
PROTECT(ARG(i,v)); /* so the new 1-sin^2 doesn't just get
rewritten as cos^2 again before it's
expanded. Since expand works on the
sum the PROTECTion won't stop it. */
}
else
ARGREP(v,i,u);
}
if(success)
{ if(powerflag)
copy(v,next); /* without simplifying */
else
polyval(v,next);
return 0;
}
return 1;
}
if(FUNCTOR(t) == '*')
{ n = ARITY(t);
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == COS)
{ err = cossqtosinsq(u,arg,&temp,reason);
if(!err)
{ path[0] = '*';
path[1] = i+1;
path[2] = 0;
set_pathtail(path);
break;
}
}
}
if(i==n)
return 1;
*next = make_term('*',n);
for(j=0;j<n;j++)
{ if(j==i)
ARGREP(*next,j,temp);
else
ARGREP(*next,j,ARG(j,t));
}
return 0;
}
if(FUNCTOR(t) == '-')
{ err = cossqtosinsq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = tnegate(temp);
path[0] = '-';
path[1] = 1;
path[2] = 0;
if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
pathcat(path,get_pathtail());
set_pathtail(path);
return 0;
}
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != COS)
return 1;
u = ARG(0,ARG(0,t));
if(!equals(ARG(1,t),two))
{ err = cancel(ARG(1,t),two,&temp,&v);
if(err)
return 1;
*next = make_power(sum(one,tnegate(make_power(sin1(u),two))),v);
}
else /* exponent is two */
*next = sum(one,tnegate(make_power(sin1(u),two)));
HIGHLIGHT(*next);
strcpy(reason,"$cos^2 u = 1 - sin^2 u$");
release(cancelgcd); /* in case inhibited by trigrationalize1 etc. */
return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int sinsqtocossq(term t, term arg, term *next, char *reason)
/* sin^2 u = 1 - cos^2 u. But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
*/
{ term u,v,temp,c,s;
int i,j,err;
int powerflag;
unsigned short n;
int success = 0;
unsigned short path[11];
if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
return sqinfract(t,SIN,next,reason);
if(FUNCTOR(t) == '=')
{ if(FUNCTOR(ARG(0,t)) == '^' &&
FUNCTOR(ARG(0,ARG(0,t))) == SIN &&
iseven(ARG(1,ARG(0,t)))
)
{ err = sinsqtocossq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(temp,ARG(1,t));
path[0] = '=';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
return 0;
}
else if(FUNCTOR(ARG(1,t)) == '^' &&
FUNCTOR(ARG(0,ARG(1,t))) == SIN &&
iseven(ARG(1,ARG(1,t)))
)
{ err = sinsqtocossq(ARG(1,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(ARG(0,t),temp);
path[0] = '=';
path[1] = 2;
path[2] = 0;
set_pathtail(path);
return 0;
}
}
if(FUNCTOR(t)== '+' && contains(t,SIN))
{ n = ARITY(t);
v = make_term('+',n);
powerflag = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
err = sinsqtocossq(u,arg,&temp,reason);
if(!err)
{ ARGREP(v,i,temp);
success = 1;
path[0] = '+';
path[1] = i+1;
path[2] = 0;
if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
pathcat(path,get_pathtail());
set_pathtail(path);
/* Now set powerflag if we don't want to call polyval on the result
because that will produce a too-large step for a student */
temp = NEGATIVE(u) ? ARG(0,u) : u;
if(FUNCTOR(temp) == '*')
{ ratpart2(temp,&c,&s);
temp = s;
}
if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
powerflag = 1;
if(FUNCTOR(temp) == '*')
powerflag = 1;
PROTECT(ARG(i,v)); /* so the new 1-cos^2 doesn't just get
rewritten as sin^2 again before it's
expanded. Since expand works on the
sum the PROTECTion won't stop it. */
}
else
ARGREP(v,i,u);
}
if(success)
{ if(powerflag)
copy(v,next);
else
polyval(v,next);
return 0;
}
return 1;
}
if(FUNCTOR(t) == '*')
{ n = ARITY(t);
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == SIN)
{ err = sinsqtocossq(u,arg,&temp,reason);
if(!err)
{ path[0] = '*';
path[1] = i+1;
path[2] = 0;
set_pathtail(path);
break;
}
}
}
if(i==n)
return 1;
*next = make_term('*',n);
for(j=0;j<n;j++)
{ if(j==i)
ARGREP(*next,j,temp);
else
ARGREP(*next,j,ARG(j,t));
}
return 0;
}
if(FUNCTOR(t) == '-')
{ err = sinsqtocossq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = tnegate(temp);
path[0] = '-';
path[1] = 1;
path[2] = 0;
if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
pathcat(path,get_pathtail());
set_pathtail(path);
return 0;
}
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != SIN)
return 1;
u = ARG(0,ARG(0,t));
if(!equals(ARG(1,t),two))
{ err = cancel(ARG(1,t),two,&temp,&v);
if(err)
return 1;
*next = make_power(sum(one,tnegate(make_power(cos1(u),two))),v);
}
else /* exponentis two */
*next = sum(one,tnegate(make_power(cos1(u),two)));
HIGHLIGHT(*next);
strcpy(reason,"$sin^2 u = 1 - cos^2 u$");
release(cancelgcd); /* in case inhibited by trigrationalize1 etc. */
return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int tansqtosecsq(term t, term arg, term *next, char *reason)
/* tan^2 u = sec^2 u - 1. But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
*/
{ term u,v,temp,c,s;
int i,j,err,powerflag;
unsigned short n;
unsigned short path[11];
int success = 0;
if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
return sqinfract(t,TAN,next,reason);
if(FUNCTOR(t) == '=')
{ if(FUNCTOR(ARG(0,t)) == '^' &&
FUNCTOR(ARG(0,ARG(0,t))) == TAN &&
iseven(ARG(1,ARG(0,t)))
)
{ err = tansqtosecsq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(temp,ARG(1,t));
path[0] = '=';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
return 0;
}
else if(FUNCTOR(ARG(1,t)) == '^' &&
FUNCTOR(ARG(0,ARG(1,t))) == TAN &&
iseven(ARG(1,ARG(1,t)))
)
{ err = tansqtosecsq(ARG(1,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(ARG(0,t),temp);
path[0] = '=';
path[1] = 2;
path[2] = 0;
set_pathtail(path);
return 0;
}
}
if(FUNCTOR(t)== '+' && contains(t,TAN))
{ n = ARITY(t);
v = make_term('+',n);
powerflag = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
err = tansqtosecsq(u,arg,&temp,reason);
if(!err)
{ ARGREP(v,i,temp);
success = 1;
path[0] = '+';
path[1] = i+1;
path[2] = 0;
if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
pathcat(path,get_pathtail());
set_pathtail(path);
/* Now set powerflag if we don't want to call polyval on the result
because that will produce a too-large step for a student */
temp = NEGATIVE(u) ? ARG(0,u) : u;
if(FUNCTOR(temp) == '*')
{ ratpart2(temp,&c,&s);
temp = s;
}
if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
powerflag = 1;
if(FUNCTOR(temp) == '*')
powerflag = 1;
PROTECT(ARG(i,v)); /* so the new sec^2-1 doesn't just get
rewritten as tan^2 again before it's
expanded. Since expand works on the
sum the PROTECTion won't stop it. */
}
else
ARGREP(v,i,u);
}
if(success)
{ if(powerflag)
copy(v,next);
else
polyval(v,next);
return 0;
}
return 1;
}
if(FUNCTOR(t) == '*')
{ n = ARITY(t);
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == TAN)
{ err = tansqtosecsq(u,arg,&temp,reason);
if(!err)
{ path[0] = '*';
path[1] = i+1;
path[2] = 0;
set_pathtail(path);
break;
}
}
}
if(i==n)
return 1;
*next = make_term('*',n);
for(j=0;j<n;j++)
{ if(j==i)
ARGREP(*next,j,temp);
else
ARGREP(*next,j,ARG(j,t));
}
return 0;
}
if(FUNCTOR(t) == '-')
{ err = tansqtosecsq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = tnegate(temp);
path[0] = '-';
path[1] = 1;
path[2] = 0;
if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
pathcat(path,get_pathtail());
set_pathtail(path);
return 0;
}
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != TAN)
return 1;
u = ARG(0,ARG(0,t));
if(!equals(ARG(1,t),two))
{ err = cancel(ARG(1,t),two,&temp,&v);
if(err)
return 1;
*next = make_power(sum(make_power(sec1(u),two),minusone),v);
}
else /* exponentis two */
*next = sum(make_power(sec1(u),two),minusone);
HIGHLIGHT(*next);
strcpy(reason,"$tan^2 u = sec^2 u - 1$");
return 0;
}
/*___________________________________________________________*/
MEXPORT_ALGEBRA int secsqtotansq(term t, term arg, term *next, char *reason)
/* sec^2 u = tan^2 u + 1. But it also works on a sum, applying
this identity wherever possible to summands, even if the
summands are multiplied by constants, and simplifying the result.
*/
{ term u,v,temp,c,s;
int i,j,err,powerflag;
unsigned short path[11];
unsigned short n;
int success = 0;
if(FUNCTOR(t) == '/' && get_mathmode() == AUTOMODE)
return sqinfract(t,SEC,next,reason);
if(FUNCTOR(t) == '=')
{ if(FUNCTOR(ARG(0,t)) == '^' &&
FUNCTOR(ARG(0,ARG(0,t))) == SEC &&
iseven(ARG(1,ARG(0,t)))
)
{ err = secsqtotansq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(temp,ARG(1,t));
path[0] = '=';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
return 0;
}
else if(FUNCTOR(ARG(1,t)) == '^' &&
FUNCTOR(ARG(0,ARG(1,t))) == TAN &&
iseven(ARG(1,ARG(1,t)))
)
{ err = secsqtotansq(ARG(1,t),arg,&temp,reason);
if(err)
return 1;
*next = equation(ARG(0,t),temp);
path[0] = '=';
path[1] = 2;
path[2] = 0;
set_pathtail(path);
return 0;
}
}
if(FUNCTOR(t)== '+' && contains(t,SEC))
{ n = ARITY(t);
v = make_term('+',n);
powerflag = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
err = secsqtotansq(u,arg,&temp,reason);
if(!err)
{ ARGREP(v,i,temp);
success = 1;
path[0] = '+';
path[1] = i+1;
path[2] = 0;
if(FUNCTOR(u) == '*' || FUNCTOR(u) == '-')
pathcat(path,get_pathtail());
set_pathtail(path);
/* Now set powerflag if we don't want to call polyval on the result
because that will produce a too-large step for a student */
temp = NEGATIVE(u) ? ARG(0,u) : u;
if(FUNCTOR(temp) == '*')
{ ratpart2(temp,&c,&s);
temp = s;
}
if(FUNCTOR(temp) == '^' && !equals(ARG(1,temp),two))
powerflag = 1;
if(FUNCTOR(temp) == '*')
powerflag = 1;
PROTECT(ARG(i,v)); /* so the new tan^2-1 doesn't just get
rewritten as sec^2 again before it's
expanded. Since expand works on the
sum the PROTECTion won't stop it. */
}
else
ARGREP(v,i,u);
}
if(success)
{ if(powerflag)
copy(v,next);
else
polyval(v,next);
return 0;
}
return 1;
}
if(FUNCTOR(t) == '*')
{ n = ARITY(t);
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == SEC)
{ err = secsqtotansq(u,arg,&temp,reason);
if(!err)
{ path[0] = '*';
path[1] = i+1;
path[2] = 0;
set_pathtail(path);
break;
}
}
}
if(i==n)
return 1;
*next = make_term('*',n);
for(j=0;j<n;j++)
{ if(j==i)
ARGREP(*next,j,temp);
else
ARGREP(*next,j,ARG(j,t));
}
return 0;
}
if(FUNCTOR(t) == '-')
{ err = secsqtotansq(ARG(0,t),arg,&temp,reason);
if(err)
return 1;
*next = tnegate(temp);
path[0] = '-';
path[1] = 1;
path[2] = 0;
if(FUNCTOR(ARG(0,t)) == '*' || FUNCTOR(ARG(0,t)) == '+')
pathcat(path,get_pathtail());
set_pathtail(path);
return 0;
}
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != SEC)
return 1;
u = ARG(0,ARG(0,t));
if(!equals(ARG(1,t),two))
{ err = cancel(ARG(1,t),two,&temp,&v);
if(err)
return 1;
*next = make_power(sum(make_power(tan1(u),two),one),v);
}
else /* exponentis two */
*next = sum(make_power(tan1(u),two),one);
HIGHLIGHT(*next);
strcpy(reason,"$sec^2 u = tan^2 u + 1$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sinsum(term t, term arg, term *next, char *reason)
/* sin(u+v) = sin u cos v + cos u sin v */
{ term u,v;
unsigned short n;
int i;
if(FUNCTOR(t) != SIN)
return 1;
if(FUNCTOR(ARG(0,t)) != '+')
return 1;
n = ARITY(ARG(0,t));
u = ARG(0,ARG(0,t));
if(n == 2)
{ v = ARG(1,ARG(0,t));
if(FUNCTOR(v) == '-')
return 1; /* use sindif instead */
}
else
{ v = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(v,i,ARG(i+1,ARG(0,t)));
}
*next = sum(product(sin1(u),cos1(v)),product(cos1(u),sin1(v)));
HIGHLIGHT(*next);
strcpy(reason,"sin(u+v)=sin u cos v + cos u sin v");
check_periodic(t);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sindif(term t, term arg, term *next, char *reason)
/* sin(u-v) = sin u cos v - cos u sin v */
{ term u,v;
unsigned short n;
int i;
if(FUNCTOR(t) != SIN)
return 1;
if(FUNCTOR(ARG(0,t)) != '+')
return 1;
n = ARITY(ARG(0,t));
if(n == 2 && FUNCTOR(ARG(0,ARG(0,t))) == '-')
{ v = ARG(0,ARG(0,ARG(0,t)));
u = ARG(1,ARG(0,t));
}
else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
return 1;
else if(n == 2)
{ u = ARG(0,ARG(0,t));
v = ARG(0,ARG(1,ARG(0,t)));
}
else if(n > 2) /* works only if last arg has a minus sign */
{ if(FUNCTOR(ARG(n-1,ARG(0,t))) != '-')
return 1;
v = ARG(0,ARG(n-1,ARG(0,t)));
u = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(u,i,ARG(i,ARG(0,t)));
}
*next = sum(product(sin1(u),cos1(v)),tnegate(product(cos1(u),sin1(v))));
HIGHLIGHT(*next);
strcpy(reason,"sin(u-v)=sin u cos v - cos u sin v");
check_periodic(t);
check_complementary(t);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cossum(term t, term arg, term *next, char *reason)
/* cos(u+v) = cos u cos v - sin u sin v */
{ term u,v;
unsigned short n;
int i;
if(FUNCTOR(t) != COS)
return 1;
if(FUNCTOR(ARG(0,t)) != '+')
return 1;
u = ARG(0,ARG(0,t));
n = ARITY(ARG(0,t));
if(n == 2)
{ v = ARG(1,ARG(0,t));
if(FUNCTOR(v) == '-')
return 1; /* use cosdif instead */
}
else
{ v = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(v,i,ARG(i+1,ARG(0,t)));
}
*next = sum(product(cos1(u),cos1(v)),tnegate(product(sin1(u),sin1(v))));
HIGHLIGHT(*next);
strcpy(reason,"cos(u+v)=cos u cos v - sin u sin v");
check_periodic(t);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cosdif(term t, term arg, term *next, char *reason)
/* cos(u-v)= cos u cos v + sin u sin v */
{ term u,v;
unsigned short n;
int i;
if(FUNCTOR(t) != COS)
return 1;
if(FUNCTOR(ARG(0,t)) != '+')
return 1;
n = ARITY(ARG(0,t));
if(n == 2 && FUNCTOR(ARG(0,ARG(0,t))) == '-')
{ v = ARG(0,ARG(0,ARG(0,t)));
u = ARG(1,ARG(0,t));
}
else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
return 1;
else if(n==2)
{ u = ARG(0,ARG(0,t));
v = ARG(0,ARG(1,ARG(0,t)));
}
else if(n > 2) /* works only if last arg has a minus sign */
{ if(FUNCTOR(ARG(n-1,ARG(0,t))) != '-')
return 1;
v = ARG(0,ARG(n-1,ARG(0,t)));
u = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(u,i,ARG(i,ARG(0,t)));
}
*next = sum(product(cos1(u),cos1(v)),product(sin1(u),sin1(v)));
HIGHLIGHT(*next);
strcpy(reason,"cos(u-v)=cos u cos v + sin u sin v");
check_periodic(t);
check_complementary(t);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tansum(term t, term arg, term *next, char *reason)
/* tan(u+v) = (tan u + tan v)/ (1-tan u tan v) */
{ term u,v,tanu,tanv,s;
unsigned short n;
int i,err;
if(FUNCTOR(t) != TAN)
return 1;
s = ARG(0,t); /* t = tan s */
if(FUNCTOR(s) != '+')
return 1;
n = ARITY(s);
u = ARG(0,s);
if(n == 2)
{ v = ARG(1,s);
if(FUNCTOR(v) == '-')
{ if(get_mathmode() == AUTOMODE)
return 1; /* use tandif instead */
if(status(tansum) <= LEARNING)
{ errbuf(0, english(1125));
/* Use the formula for tan(u-v) instead. */
return 1;
}
}
}
else
{ v = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(v,i,ARG(i+1,s));
}
tanu = tan1(u);
tanv = tan1(v);
if(equals(v,piover2) || equals(u,piover2))
goto fail;
err = check(domain(tanu));
if(err)
goto fail;
err = check(domain(tanv));
if(err)
goto fail;
*next = make_fraction(sum(tanu,tanv),sum(one,tnegate(product(tanu,tanv))));
HIGHLIGHT(*next);
strcpy(reason, "tan(u+v) = ...");
/* display_reason can now cope with $-$ text to be parsed and displayed */
check_periodic(t);
return 0;
fail:
errbuf(0,english(1126));
/* That would result in an undefined value of tan. */
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int tandif(term t, term arg, term *next, char *reason)
/* tan(u-v) = (tan u - tan v)/ (1+tan u tan v) */
{ term u,v,tanu,tanv,s;
unsigned short n;
int i,err;
if(FUNCTOR(t) != TAN)
return 1;
s = ARG(0,t); /* t = tan s */
if(FUNCTOR(s) != '+')
return 1;
n = ARITY(s);
if(n == 2 && FUNCTOR(ARG(0,s)) == '-')
{ v = ARG(0,ARG(0,s));
u = ARG(1,s);
}
else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
return 1;
else if(n == 2)
{ u = ARG(0,s);
v = ARG(0,ARG(1,s));
}
else /* if(n > 2) */
{ if(FUNCTOR(ARG(n-1,s)) != '-')
return 1; /* it works only if last arg has a minus sign */
v = ARG(0,ARG(n-1,s));
u = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(u,i,ARG(i,ARG(0,t)));
}
tanu = tan1(u);
tanv = tan1(v);
if(equals(v,piover2) || equals(u,piover2))
goto fail;
err = check(domain(tanu));
if(err)
goto fail;
err = check(domain(tanv));
if(err)
goto fail;
*next = make_fraction(sum(tanu,tnegate(tanv)),sum(one,product(tanu,tanv)));
HIGHLIGHT(*next);
strcpy(reason,"tan(u-v) = ...");
check_periodic(t);
return 0;
fail:
errbuf(0,english(1126));
/* That would result in an undefined value of tan. */
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cotsum(term t, term arg, term *next, char *reason)
/* cot(u+v)=(cot u cot v-1)/(cot u+cot v) */
/* The right side can be undefined when the left is not,
for instance cot(u+�) always gives an undefined right side. */
{ term u,v,cotu,cotv,s,num,denom,w,cancelled;
unsigned short n;
int i,err;
if(FUNCTOR(t) != COT)
return 1;
s = ARG(0,t); /* t = cot s */
if(FUNCTOR(s) != '+')
return 1;
n = ARITY(s);
u = ARG(0,s);
if(equals(u,pi))
{ errbuf(0, english(1124)); /* cot pi is undefined */
return 1;
}
if(FUNCTOR(u) == '*' && !cancel(u,pi,&cancelled,&w) && isinteger(u))
{ errbuf(0, english(1655));
/* cot m pi is undefined */
return 1;
}
if(n == 2)
{ v = ARG(1,s);
if(equals(v,pi))
{ errbuf(0, english(1655));
return 1;
}
if(FUNCTOR(v) == '*' && !cancel(v,pi,&cancelled,&w) && isinteger(w))
{ errbuf(0, english(1655));
/* cot m pi is undefined */
return 1;
}
if(FUNCTOR(v) == '-')
return 1; /* use cotdif instead */
}
else
{ v = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(v,i,ARG(i+1,s));
}
cotu = cot1(u);
cotv = cot1(v);
if(equals(v,pi) || equals(u,pi))
goto fail;
err = check(domain(cotu));
if(err)
goto fail;
err = check(domain(cotv));
if(err)
goto fail;
num = sum(product(cotu,cotv),minusone);
denom = sum(cotu,cotv);
*next = make_fraction(num,denom);
HIGHLIGHT(*next);
strcpy(reason,"cot(u+v) = ...");
check_periodic(t);
return 0;
fail:
errbuf(0,english(1127));
/* That would result in an undefined value of cot. */
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int cotdif(term t, term arg, term *next, char *reason)
/* cot(u-v)=(1+cot u cot v)/(cot v-cot u) */
{ term u,v,cotu,cotv,s,num,denom;
unsigned short n;
int i,err;
if(FUNCTOR(t) != COT)
return 1;
s = ARG(0,t); /* t = cot s */
if(FUNCTOR(s) != '+')
return 1;
n = ARITY(s);
if(n == 2 && FUNCTOR(ARG(0,s)) == '-')
{ v = ARG(0,ARG(0,s));
u = ARG(1,s);
}
else if(n == 2 && FUNCTOR(ARG(1,ARG(0,t))) != '-')
return 1;
else if(n == 2)
{ u = ARG(0,s);
v = ARG(0,ARG(1,s));
}
else /* if(n > 2) */
{ if(FUNCTOR(ARG(n-1,s)) != '-')
return 1; /* it works only if last arg has a minus sign */
v = ARG(0,ARG(n-1,s));
u = make_term('+',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(u,i,ARG(i,ARG(0,t)));
}
cotu = cot1(u);
cotv = cot1(v);
if(equals(v,pi) || equals(u,pi))
goto fail;
err = check(domain(cotu));
if(err)
goto fail;
err = check(domain(cotv));
if(err)
goto fail;
num = sum(one, product(cotu,cotv));
denom = sum(cotv, tnegate(cotu));
*next = make_fraction(num,denom);
HIGHLIGHT(*next);
strcpy(reason,"cot(u-v) = ...");
check_periodic(t);
return 0;
fail:
errbuf(0,english(1127));
/* That would result in an undefined value of cot. */
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublecos1(term t, term arg, term *next, char *reason)
/* cos^2 a - sin^2 a = cos 2a */
{ term lhs,rhs,a;
int err;
lhs = sum(make_power(cos1(var0),two),tnegate(make_power(sin1(var0),two)));
rhs = cos1(product(two,var0));
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 a-sin^2 a=cos 2a$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublecos2(term t, term arg, term *next, char *reason)
/* 1 - 2 sin^2 � = cos(2�) */
{ term lhs,rhs,a;
int err;
lhs = sum(one,tnegate(product(two,make_power(sin1(var0),two))));
rhs = cos1(product(two,var0));
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,"$1 - 2 sin^2 � = cos 2�$");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversedoublecos3(term t, term arg, term *next, char *reason)
/* 2 cos^2 � - 1 = cos(2�) */
{ term lhs,rhs,a;
int err;
lhs = sum(product(two,make_power(cos1(var0),two)),minusone);
rhs = cos1(product(two,var0));
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,"$2 cos^2 � - 1 = cos 2�$");
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int sinoddpower(term t, term arg, term *next, char *reason)
/* sin^(2n+1) u = sin u (1-cos^2 u)^n */
{ term u,n;
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != SIN)
return 1;
polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
if(!isinteger(n))
return 1;
u = ARG(0,ARG(0,t));
*next = product(sin1(u), make_power(sum(one, tnegate(make_power(cos1(u),two))),n));
HIGHLIGHT(*next);
strcpy(reason,"sin^(2n+1) u = sin u (1-cos^2 u)^n");
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int cosoddpower(term t, term arg, term *next, char *reason)
/* cos^(2n+1) u = cos u (1-sin^2 u)^n */
{ term u,n;
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != COS)
return 1;
polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
if(!isinteger(n))
return 1;
u = ARG(0,ARG(0,t));
*next = product(cos1(u), make_power(sum(one, tnegate(make_power(sin1(u),two))),n));
HIGHLIGHT(*next);
strcpy(reason,"cos^(2n+1) u = cos u (1-sin^2 u)^n");
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int tanoddpower(term t, term arg, term *next, char *reason)
/* tan^(2n+1) u = tan u (sec^2 u-1)^n */
{ term u,n;
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != TAN)
return 1;
polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
if(!isinteger(n))
return 1;
u = ARG(0,ARG(0,t));
*next = product(tan1(u), make_power(sum(make_power(sec1(u),two),minusone),n));
HIGHLIGHT(*next);
strcpy(reason,"tan^(2n+1) u = tan u (sec^2 u - 1)^n");
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int secoddpower(term t, term arg, term *next, char *reason)
/* sec^(2n+1) u = sec u (tan^2 u+1)^n */
{ term u,n;
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != SEC)
return 1;
polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
if(!isinteger(n))
return 1;
u = ARG(0,ARG(0,t));
*next = product(sec1(u), make_power(sum(make_power(tan1(u),two),one),n));
HIGHLIGHT(*next);
strcpy(reason,"sec^(2n+1) u = sec u (tan^2 u + 1)^n");
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int cscoddpower(term t, term arg, term *next, char *reason)
/* csc^(2n+1) u = csc u (cot^2 u+1)^n */
{ term u,n;
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != SEC)
return 1;
polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
if(!isinteger(n))
return 1;
u = ARG(0,ARG(0,t));
*next = product(csc1(u), make_power(sum(make_power(cot1(u),two),one),n));
HIGHLIGHT(*next);
strcpy(reason,"csc^(2n+1) u = csc u (cot^2 u + 1)^n");
return 0;
}
/*_____________________________________________________________________*/
MEXPORT_ALGEBRA int cotoddpower(term t, term arg, term *next, char *reason)
/* cot^(2n+1) u = cot u (csc^2 u-1)^n */
{ term u,n;
if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != SEC)
return 1;
polyval(make_fraction(sum(ARG(1,t),minusone),two),&n);
if(!isinteger(n))
return 1;
u = ARG(0,ARG(0,t));
*next = product(cot1(u), make_power(sum(make_power(csc1(u),two),minusone),n));
HIGHLIGHT(*next);
strcpy(reason,"cot^(2n+1) u = cot u (csc^2 u - 1)^n");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int reversesinsq(term t, term arg, term *next, char *reason)
/* 1-cos � = 2 sin^2(�/2) */
{ term lhs,rhs,a;
int err;
lhs = sum(one, tnegate(cos1(var0)));
rhs = product(two, make_power(sin1(make_fraction(var0,two)),two));
err = match(t,lhs,rhs,&a,next); /* instantiate a and *next */
if(err)
{ destroy_term(lhs);
return 1;
}
HIGHLIGHT(*next);
strcpy(reason,"$1-cos u = 2 sin^2(u/2)$");
return 0;
}
/*___________________________________________________________________*/
static void check_periodic(term t)
/* called to generate a comment when a periodicity law is
given a longer proof using trig addition formulae. */
{ unsigned short f;
term u,v,p,q,temp;
char buffer[DIMREASONBUFFER];
int err;
if(get_mathmode() != AUTOMODE)
return; /* only do this in automode */
if(get_currenttopic() != _trig_addition)
return; /* and only under this one topic */
f = FUNCTOR(t);
if(!TRIGFUNCTOR(f))
return;
u = ARG(0,t);
if(FUNCTOR(u) != '+' || ARITY(u) != 2)
return;
v = ARG(1,u);
if(NEGATIVE(v))
v = ARG(0,v);
if(equals(v,pi))
err = 0;
else if(FUNCTOR(v) == '*')
err = cancel(v,pi,&p,&q);
else
err = 1;
if(err)
return;
switch(f)
{ case SIN:
err = sinperiodic(t,zero,&temp,buffer);
break;
case COS:
err = cosperiodic(t,zero,&temp,buffer);
break;
case TAN:
err = tanperiodic(t,zero,&temp,buffer);
break;
case SEC:
err = secperiodic(t,zero,&temp,buffer);
break;
case CSC:
err = cscperiodic(t,zero,&temp,buffer);
break;
case COT:
err = cotperiodic(t,zero,&temp,buffer);
break;
}
if(err)
return;
commentbuf(0, english(1871));
commentbuf(1, english(1872));
/* Because the topic is Trig Addition, a solution using
a trig addition formula will be given, instead of
a shorter solution using periodicity. */
}
/*___________________________________________________________________*/
static void check_complementary(term t)
/* called to generate a comment when a complentarity law is
given a longer proof using trig addition formulae. */
{ unsigned short f;
term u,temp;
char buffer[DIMREASONBUFFER];
int err;
if(get_mathmode() != AUTOMODE)
return; /* only do this in automode */
if(get_currenttopic() != _trig_addition)
return; /* and only under this one topic */
f = FUNCTOR(t);
if(!TRIGFUNCTOR(f))
return;
u = ARG(0,t);
if(FUNCTOR(u) != '+' || ARITY(u) != 2)
return;
if(!NEGATIVE(ARG(1,u)))
return;
if(!equals(ARG(0,u),piover2))
return;
switch(f)
{ case SIN:
err = sintocos(t,zero,&temp,buffer);
break;
case COS:
err = costosin(t,zero,&temp,buffer);
break;
}
if(err)
return;
commentbuf(0, english(1871));
commentbuf(1, english(1872));
commentbuf(2, english(1873));
/* Because the topic is Trig Addition, a proof using
a trig addition formula will be given, instead of a one-step
solution by quoting the law stated here as the problem. */
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int makesinpower(term t, term arg, term *next, char *reason)
/* (1-cos x)^n(1+cos x)^n = sin^2n x */
/* But it also works on things like (1-cos x)^2(1+cos x)^3,
leaving a factor of (1+cos x) left over.
We don't use 'match' since it won't check two levels of
re-ordering.
*/
{ term a,b,c,u,v,w,w2,x,power,power2,extra;
int i,j,count;
unsigned short n;
if(FUNCTOR(t) != '*')
return 1;
n = ARITY(t);
count = 0;
/* quickly count the powers of sums in t, and fail if there are not 2 */
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == '+')
++count;
}
if(count < 2)
return 1;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) != '^' ||
FUNCTOR(ARG(0,u)) != '+' ||
ARITY(ARG(0,u)) != 2 ||
!isinteger(ARG(1,u))
)
continue;
power = ARG(1,u);
w = ARG(0,u);
if(ONE(ARG(0,w)) && FUNCTOR(ARG(1,w)) == COS)
x = ARG(0,ARG(1,w));
else if(ONE(ARG(1,w)) && FUNCTOR(ARG(0,w)) == COS)
x = ARG(0,ARG(0,w));
else
continue;
for(j=0;j<n;j++)
{ if(j==i)
continue;
v = ARG(j,t);
if(FUNCTOR(v) == '^' &&
FUNCTOR(ARG(0,v)) == '+' &&
ARITY(ARG(0,v)) == 2 &&
isinteger(ARG(1,v))
)
{ w2 = ARG(0,v);
power2 = ARG(1,v);
if(ONE(ARG(0,w2)) && NEGATIVE(ARG(1,w2)) &&
FUNCTOR(ARG(0,ARG(1,w2))) == COS &&
equals(ARG(0,ARG(0,ARG(1,w2))),x)
)
goto out;
}
}
}
return 1;
out:
if(equals(power,power2))
{ polyval(product(two,power),&a);
*next = make_power(sin1(x),a);
HIGHLIGHT(*next);
strcpy(reason,"$(1-cos t)�(1+cos t)� = sin^(2n) t$");
return 0;
}
if(ISINTEGER(power) && ISINTEGER(power2))
{ if (INTDATA(power) < INTDATA(power2))
{ a = make_int(INTDATA(power));
b = make_int(INTDATA(power2)-INTDATA(power));
extra = make_power(w2,b);
}
else
{ a = make_int(INTDATA(power2));
b = make_int(INTDATA(power)-INTDATA(power2));
extra = make_power(w,b);
}
}
else
{ polyval(sum(power,tnegate(power2)),&b);
if(obviously_positive(b))
{ a = power2;
extra = make_power(w,b);
}
else if(obviously_positive(strongnegate(b)))
{ b = strongnegate(b);
a = power;
extra = make_power(w2,b);
}
}
polyval(product(two,a),&c);
*next = product(make_power(sin1(x),c),extra);
HIGHLIGHT(*next);
strcpy(reason,"$(1-cos t)�(1+cos t)� = sin^(2n) t$");
return 0;
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int makecospower(term t, term arg, term *next, char *reason)
/* (1-sin x)^n(1+sin x)^n = cos^2n x */
/* But it also works on things like (1-sin x)^2(1+sin x)^3,
leaving a factor of (1+sin x) left over.
*/
{ term a,b,c,u,v,w,w2,x,power,power2,extra;
int i,j,count;
unsigned short n;
if(FUNCTOR(t) != '*')
return 1;
n = ARITY(t);
count = 0;
/* quickly count the powers of sums in t, and fail if there are not 2 */
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == '+')
++count;
}
if(count < 2)
return 1;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(FUNCTOR(u) != '^' ||
FUNCTOR(ARG(0,u)) != '+' ||
ARITY(ARG(0,u)) != 2 ||
!isinteger(ARG(1,u))
)
continue;
power = ARG(1,u);
w = ARG(0,u);
if(ONE(ARG(0,w)) && FUNCTOR(ARG(1,w)) == SIN)
x = ARG(0,ARG(1,w));
else if(ONE(ARG(1,w)) && FUNCTOR(ARG(0,w)) == SIN)
x = ARG(0,ARG(0,w));
else
continue;
for(j=0;j<n;j++)
{ if(j==i)
continue;
v = ARG(j,t);
if(FUNCTOR(v) == '^' &&
FUNCTOR(ARG(0,v)) == '+' &&
ARITY(ARG(0,v)) == 2 &&
isinteger(ARG(1,v))
)
{ w2 = ARG(0,v);
power2 = ARG(1,v);
if(ONE(ARG(0,w2)) && NEGATIVE(ARG(1,w2)) &&
FUNCTOR(ARG(0,ARG(1,w2))) == SIN &&
equals(ARG(0,ARG(0,ARG(1,w2))),x)
)
goto out;
}
}
}
return 1;
out:
if(equals(power,power2))
{ polyval(product(two,power),&a);
*next = make_power(cos1(x),a);
HIGHLIGHT(*next);
strcpy(reason,"$(1-sin t)�(1+sin t)� = cos^(2n) t$");
return 0;
}
if(ISINTEGER(power) && ISINTEGER(power2))
{ if (INTDATA(power) < INTDATA(power2))
{ a = make_int(INTDATA(power));
b = make_int(INTDATA(power2)-INTDATA(power));
extra = make_power(w2,b);
}
else
{ a = make_int(INTDATA(power2));
b = make_int(INTDATA(power)-INTDATA(power2));
extra = make_power(w,b);
}
}
else
{ polyval(sum(power,tnegate(power2)),&b);
if(obviously_positive(b))
{ a = power2;
extra = make_power(w,b);
}
else if(obviously_positive(strongnegate(b)))
{ b = strongnegate(b);
a = power;
extra = make_power(w2,b);
}
}
polyval(product(two,a),&c);
*next = product(make_power(cos1(x),c),extra);
HIGHLIGHT(*next);
strcpy(reason,"$(1-sin t)�(1+sin t)� = cos^(2n) t$");
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists