Sindbad~EG File Manager
/* M. Beeson, simple differentiation operators for MathXpert */
/*
1.14.91 original date
2.27.98 last modified
3.10.99 corrected difabs2
11.16.00 corrected fundamentaltheorem2 on indefinite integrals
6.3.05 corrected typo at line 902
*/
#include <string.h>
#include <assert.h>
#define TRIGCALC_DLL
#include "globals.h"
#include "ops.h"
#include "calc.h"
#include "polynoms.h"
#include "probtype.h"
#include "deriv.h"
#include "cancel.h"
#include "order.h"
#include "factor.h"
#include "algaux.h"
#include "getprob.h"
#include "prover.h"
#include "symbols.h"
#include "errbuf.h"
#include "relrates.h"
#include "autosimp.h" /* SetShowStepOperation */
#include "dispfunc.h"
#include "deval.h"
#include "pvalaux.h" /* twoparts */
static term dif_aux2(term u, term x);
/*_______________________________________________________________________*/
static void difdef_warning(term t)
/* If a user tries to differentiate e.g. x^(1/2) from definition,
they will get a comment about the difficulty of the resulting limit. */
{ if(FUNCTOR(t) == '^' && FRACTION(ARG(1,t)) && equals(ARG(1,ARG(1,t)),two))
{ commentbuf(0, english(1034));
/* You might do better to work with �x instead of x^�. */
return;
}
/* More cases can be explained here if required. */
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int defnofderivative(term t, term arg, term *next, char *reason)
{ term h; /* for the limit variable */
term x,u,a,q;
int nvariables;
varinf *varinfo = get_varinfo();
term *varlist = get_varlist();
int i;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
if(!ISATOM(x)) /* supposedly such terms can't ever be created anyway */
{ errbuf(0, english(591));
/* In du/dx, x must be a variable. */
return 1;
}
u = ARG(0,t);
h = getnewvar(t,"hpqrst"); /* already adds it to the varlist */
if(FUNCTOR(h)==ILLEGAL)
{ errbuf(0, english(1448));
/* Too many subscripted variables, can't make more. */
return 1;
}
nvariables = get_nvariables();
SETORDERED(h); /* we'll make its dependency information in varinfo
show it dependent on x; order.c uses this to ensure
that xh won't get re-ordered to hx. But, we don't
mark it with SETDEPENDENT, as that screws up
stdpart, which then thinks it is dealing with a
limit at infinity. */
SETORDERED(varlist[nvariables-1]);
assert(FUNCTOR(varlist[nvariables-1]) == FUNCTOR(h)); /* it was just added */
set_eigenvariable(nvariables-1); /* make h the new eigenvariable */
/* This will make factoroutconstant treat expressions not
involving h as constant; without it automode can't differentiate
e^x from the definition of derivative */
varinfo[nvariables-1].scope = BOUND; /* specify that the new variable is
a bound variable; this will be used by actual_condition in axioms.c */
varinfo[nvariables-1].multorder = 1; /* used by multcompare1 to control
ordering of factors */
/* find out which varlist[i] is x */
for(i=0;i<nvariables;i++)
{ if(equals(varlist[i],x))
break;
}
assert(i<nvariables);
varinfo[nvariables-1].dp |= (1 << i); /* set bit i of the depends info for h */
subst(sum(x,h),x,u,&a);
q = make_term(ARROW,2);
ARGREP(q,0,h);
ARGREP(q,1,zero);
*next = limit(q,make_fraction(sum(a,tnegate(u)),h));
SETCOLOR(*next,YELLOW);
strcpy(reason, english(592)); /* defn of derivative */
difdef_warning(t);
return 0;
}
/*______________________________________________________________________*/
void set_chainrule_errmsg(void)
/*
That operation won't work here because the
expression inside the function isn't exactly
the same as the independent variable. Try the
chain rule version of the operation instead.
*/
{ errbuf(0, english(593));
errbuf(1, english(594));
errbuf(2, english(595));
errbuf(3, english(596));
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difpower(term t, term arg, term *next, char *reason)
/* works on x� and on ax�, on which it yields nax^(n-1) */
{ term a,x,u,n,p,nminusone,cancelled;
int i,err,flag;
char buffer[128];
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != '^' && FUNCTOR(u) != '*')
return 1;
if(FUNCTOR(u)== '^')
{ a= one;
p = ARG(0,u);
n = ARG(1,u);
if(!equals(p,x))
{ set_chainrule_errmsg();
return 1;
}
}
if(FUNCTOR(u)=='*')
{ for(i=0;i<ARITY(u);i++)
{ if(FUNCTOR(ARG(i,u))=='^')
{ flag=1; /* consider (3x)^2 x^2 for example;
flag gets set at (3x)^2 but we don't want to break */
if(equals(ARG(0,ARG(i,u)),x)) break;
}
}
if(i==ARITY(u))
{ if(flag)
set_chainrule_errmsg();
return 1;
}
n = ARG(1,ARG(i,u));
p = ARG(0,ARG(i,u));
cancel(u,ARG(i,u),&cancelled,&a);
}
if(depends(n,x)) /* don't use this on x^x for example */
{ strcpy(buffer, english(597)); /* The exponent depends on */
strcat(buffer,atom_string(x));
strcat(buffer,",");
errbuf(0,buffer);
errbuf(1, english(598));
/* so you can't use that operation. */
return 1;
}
strcpy(reason, english(599)); /* power rule */
if(equals(n,two))
{ *next = (FUNCTOR(u) == '^' ? product(two,x) : product3(two,a,x));
SETCOLOR(*next,YELLOW);
return 0;
}
else if (status(difpower) >= KNOWN)
{ err = value(sum(n,minusone),&nminusone);
if(err!=0 && err!=2)
nminusone = sum(n,minusone);
}
else nminusone = sum(n,minusone);
*next = (FUNCTOR(u) == '^' ? product(n,make_power(x,nminusone)) :
product3(n,a,make_power(x,nminusone))
);
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difpower2(term t, term arg, term *next, char *reason)
/* chain rule version of power rule */
{ term a,x,u,n,p,nminusone,cancelled,extra,temp;
int i;
char buffer[128];
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != '^' && FUNCTOR(u) != '*')
return 1;
if(FUNCTOR(u)== '^')
{ a= one;
p = ARG(0,u);
n = ARG(1,u);
extra = (equals(p,x) ? one : diff(p,x));
}
if(FUNCTOR(u)=='*')
{ for(i=0;i<ARITY(u);i++)
{ if(FUNCTOR(ARG(i,u))=='^' && depends(ARG(i,u),x))
break;
}
if(i==ARITY(u))
return 1;
n = ARG(1,ARG(i,u));
p = ARG(0,ARG(i,u));
extra = (equals(p,x) ? one : diff(p,x));
cancel(u,ARG(i,u),&cancelled,&a);
if(depends(a,x))
return 1; /* non-power terms must be constant */
}
if(depends(n,x)) /* don't use this on x^x for example */
{ strcpy(buffer, english(597)); /* The exponent depends on */
strcat(buffer,atom_string(x));
strcat(buffer,",");
errbuf(0,buffer);
errbuf(1, english(598));
/* so you can't use that operation. */
return 1;
}
strcpy(reason, english(599)); /* power rule */
if(equals(n,two))
{ temp = (FUNCTOR(u) == '^' ? product(two,p) : product3(two,a,p));
if(ONE(extra))
*next = temp;
else
{ *next = product(temp,extra);
RELEASE(temp);
}
SETCOLOR(*next,YELLOW);
return 0;
}
else if (status(difpower) >= KNOWN)
polyval(sum(n,minusone),&nminusone);
else nminusone = sum(n,minusone);
temp = (FUNCTOR(u) == '^' ? product(n,make_power(p,nminusone)) :
product3(n,a,make_power(p,nminusone))
);
if(ONE(extra))
*next = temp;
else
{ *next = product(temp,extra);
if(!ONE(n))
RELEASE(temp);
}
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difidentity(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(!equals(x,u))
return 1;
*next = one;
strcpy(reason,"dx/dx = 1");
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difconstant(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(depends(u,x))
return 1;
*next = zero;
SETCOLOR(*next,YELLOW);
strcpy(reason, english(600)); /* dc/dx=0 (c constant) */
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difsum(term t, term arg, term *next, char *reason)
{ term x,u;
unsigned short n;
int i;
int flag = 0; /* set when we encounter minus sign */
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
n = ARITY(u);
*next = make_term('+',n);
for(i=0;i<n;i++)
{ if(FUNCTOR(ARG(i,u)) == '-')
{ ARGREP(*next,i,tnegate(diff(ARG(0,ARG(i,u)),x)));
flag = 1;
}
else
ARGREP(*next,i,diff(ARG(i,u),x));
}
SETCOLOR(*next,YELLOW);
if(n==2 && FUNCTOR(ARG(1,u))=='-')
strcpy(reason,"(d/dx)(u-v) = du/dx-dv/dx");
else if (flag)
strcpy(reason,"$(d/dx)(u�v)$ = $du/dx�dv/dx$");
else
strcpy(reason,"(d/dx)(u+v) = du/dx+dv/dx");
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difminus(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != '-')
return 1;
*next = tnegate(diff(ARG(0,u),x));
SETCOLOR(*next,YELLOW);
strcpy(reason,"d(-y)/dx = -dy/dx");
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difproduct(term t, term arg, term *next, char *reason)
{ term x,u,temp,temp2;
unsigned short n;
int i,j;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(ATOMIC(u) || FUNCTOR(u) != '*')
return 1;
n = ARITY(u);
*next = make_term('+',n);
if(status(difproduct) <= LEARNING && n > 2)
/* then don't do more than two at a time */
{ term v = make_term('*',(unsigned short)(n-1));
for(i=1;i<n;i++)
ARGREP(v,i,ARG(i,u));
temp = make_term('*',2);
ARGREP(temp,0,ARG(0,u));
ARGREP(temp,1,v);
return difproduct(temp,arg,next,reason);
}
for(i=0;i<n;++i)
{ temp2 = make_term('*',n);
/* this term will have the n-i-1'th arg of the product differentiated
and put at the end */
for(j=0;j<n;j++)
{ arg = ARG(j,u);
if(j<n-i-1)
ARGREP(temp2,j,arg);
else if(j==n-i-1)
ARGREP(temp2,n-1,diff(arg,x));
else
ARGREP(temp2,j-1,arg);
}
sortargs(temp2);
ARGREP(*next,i,temp2);
}
if(n > 2)
additive_sortargs(*next);
/* to save a useless-looking 'order terms' step */
SETCOLOR(*next,YELLOW);
strcpy(reason, english(601)); /* product rule */
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difrecip(term t, term arg, term *next, char *reason)
{ term x,u,c,v;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != '/')
return 1;
v = ARG(1,u);
c = ARG(0,u);
if(ONE(c) && equals(v,x))
{ strcpy(reason, "(d/dx)(1/x) = -1/x^2");
*next = tnegate(make_fraction(one,make_power(x,two)));
}
else if(ONE(c))
{ strcpy(reason,"(d/dx)(1/v) = -(dv/dx)/v^2");
*next = tnegate(make_fraction(diff(v,x),make_power(v,two)));
}
else if(equals(v,x) && !depends(c,x))
{ strcpy(reason, english(602)); /* (d/dx)(c/v) = -c/v^2 (c constant) */
*next = tnegate(make_fraction(c,make_power(v,two)));
}
else if(!depends(c,x))
{ strcpy(reason, english(603));
/* (d/dx)(c/v) = -c(dv/dx)/v^2 (c constant) */
*next = tnegate(make_fraction(c,make_power(v,two)));
}
else
return 1;
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difquotient(term t, term arg, term *next, char *reason)
{ term x,u,a,b;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != '/')
return 1;
a = ARG(0,u);
b = ARG(1,u);
*next = make_fraction(
sum(product(b,diff(a,x)), tnegate(product(a,diff(b,x)))),
make_power(b,two)
);
SETCOLOR(*next,YELLOW);
strcpy(reason, english(604)); /* quotient rule */
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difroots(term t, term arg, term *next, char *reason)
{ term x,u,n,p;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u)!= ROOT)
return 1;
p = ARG(1,u);
n = ARG(0,u);
*next = diff(make_power(p,make_fraction(one,n)),x);
SETCOLOR(*next,YELLOW);
strcpy(reason,"$��x = x^(1/n)$");
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difsqrt(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u)!= SQRT)
return 1;
p = ARG(0,u);
if(!equals(p,x))
{ set_chainrule_errmsg();
return 1;
}
*next = make_fraction(one,product(two,u));
SETCOLOR(*next,YELLOW);
strcpy(reason,"$(d/dx) �x = 1/(2�x)$");
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difsqrt2(term t, term arg, term *next, char *reason)
/* chain rule version */
{ term x,u,p,num;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u)!= SQRT)
return 1;
p = ARG(0,u);
if(equals(p,x))
{ num = one;
strcpy(reason,"$(d/dx) �x = 1/(2�x)$");
}
else
{ num = diff(p,x);
strcpy(reason,"$(d/dx)�u$ = $(du/dx)/(2�u)$");
}
*next = make_fraction(num,product(two,u));
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int chainrule(term t, term arg, term *next, char *reason)
/* d/dx(f(u))=f'(u)du/dx */
{ term x,u,v,p;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(ATOMIC(u))
return 1;
if(ARITY(u) != 1)
return 1;
v = ARG(0,u);
if(ATOMIC(v))
return 1;
if(ARITY(v) != 1)
return 1;
/* so u = f(v(y)) */
p = make_term(PR,2);
ARGREP(p,0, MAKE_ATOM(FUNCTOR(u)));
ARGREP(p,1,one);
*next = product(p,diff(v,x));
strcpy(reason,"d/dx(f(u))=f'(u)du/dx");
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int primerule(term t, term arg, term *next, char *reason)
/* f'(x)= d/dx f(x) */
{ term x,u;
int err;
if(FUNCTOR(t) != PR)
return 1;
u = ARG(0,t); /* u is f(x) hopefully */
if(ATOMIC(u))
return 1;
if(ARITY(u) != 1)
return 1;
x = ARG(0,u);
if(!ATOMIC(x))
{ errbuf(0, english(605));
/* in d/dx, x must be a variable. */
return 1;
}
if(ONE(ARG(1,t)))
*next = diff(u,x);
else
{ err = check(and(type(ARG(1,t),INTEGER),positive(ARG(1,t))));
if(err)
{ errbuf(0, english(606));
/* Can't take derivatives of non-integer order */
return 1;
}
*next = diff3(u,x,ARG(1,t));
}
strcpy(reason,"f'(x)= d/dx f(x)");
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int fundamentaltheorem2(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != INTEGRAL)
return 1;
strcpy(reason, english(607)); /* fundamental theorem of calculus */
if(ARITY(u)==2) /* differentiate an indefinite integral */
{ if(!equals(x,ARG(1,u)))
return 1;
*next = ARG(0,u);
SETCOLOR(*next,YELLOW);
return 0;
}
if(ARITY(u)==4) /* differentiate a definite integral */
{ term lo,hi,t,temp,temp2,a,b;
t = ARG(1,u); /* variable of integration */
lo = ARG(2,u);
hi = ARG(3,u);
if(!depends(lo,x))
{ if(equals(x,hi))
subst(x,t,ARG(0,u),next);
else if(!depends(hi,x))
return 1;
else
{ subst(hi,t,ARG(0,u),&temp);
*next = product(temp, diff(hi,x));
}
}
else if(!depends(hi,x))
{ if(equals(x,lo))
{ subst(x,t,ARG(0,u),&temp);
tneg(temp,next);
}
else
{ subst(lo,t,ARG(0,u),&temp);
*next = tnegate(product(temp,diff(lo,x)));
}
}
else
{ subst(hi,t,ARG(0,u),&temp);
subst(lo,t,ARG(0,u),&temp2);
a = equals(hi,x) ? temp : product(temp,diff(hi,x));
b = equals(lo,x) ? temp2 : product(temp2,diff(lo,x));
*next = sum(a,tnegate(b));
}
SETCOLOR(*next,YELLOW);
return 0;
}
return 1;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int diflinear(term t, term arg, term *next, char *reason)
/* d(cu)/dx = c du/dx */
/* d/dx (u/c) = (1/c) du/dx */
{ term x,u,c,v;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FRACTION(u))
return diflinear2(t,arg,next,reason);
if(FUNCTOR(u) != '*')
return 1;
strcpy(reason,"d/dx (cu) = c du/dx");
twoparts(u,x,&c,&v);
if(ONE(c))
return 1;
if(equals(v,x))
{ *next = c;
strcpy(reason,"d/dx (cx) = c");
}
else
*next = product(c,diff(v,x));
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int diflinear2(term t, term arg, term *next, char *reason)
/* d/dx (u/c) = (1/c) du/dx */
{ term x,u,c,v,num,denom,c1,c2,v2;
if(FUNCTOR(t) != DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != '/')
return 1;
num = ARG(0,u);
denom = ARG(1,u);
twoparts(num,x,&c1,&v);
twoparts(denom,x,&c2,&v2);
if(ONE(c1) && ONE(c2))
return 1;
c = make_fraction(c1,c2);
*next = product(c,diff(make_fraction(v,v2),x));
if(ONE(c))
strcpy(reason,"d/dx (u/c)=(1/c)du/dx");
else
strcpy(reason,"d/dx (cu) = c du/dx");
SETCOLOR(*next,YELLOW);
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difinversepower(term t, term arg, term *next, char *reason)
/* d/dx (c/x�) = -nc/x^(n+1) */
{ term x,c,n,m,u;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
x = ARG(1,t);
if(FUNCTOR(ARG(0,t)) != '/')
return 1;
c = ARG(0,ARG(0,t));
if(!constant(c))
return 1;
u = ARG(1,ARG(0,t)); /* the denominator */
if(FUNCTOR(u) != '^')
return 1;
n = ARG(1,u);
if(!equals(ARG(0,u),x))
return 1;
polyval(sum(n,one),&m);
*next = tnegate(make_fraction(product(n,c),make_power(x,m)));
SETCOLOR(*next,YELLOW);
strcpy(reason,"d/dx c/x^n=-nc/x^(n+1)");
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difabs(term t, term arg, term *next, char *reason)
/* d/dx |x| = x / |x| */
{ term x;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
x = ARG(1,t);
if(FUNCTOR(ARG(0,t)) != ABS)
return 1;
if(!equals(x,ARG(0,ARG(0,t))))
return 1;
*next = make_fraction(x,abs1(x));
SETCOLOR(*next,YELLOW);
strcpy(reason,"d/dx |x| = x/|x|");
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difabs2(term t, term arg, term *next, char *reason)
/* d/dx |u|=u du/dx/|u| */
{ term x,u;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
x = ARG(1,t);
if(FUNCTOR(ARG(0,t)) != ABS)
return 1;
u = ARG(0,ARG(0,t));
*next = make_fraction(product(u,diff(u,x)),abs1(u));
HIGHLIGHT(*next);
strcpy(reason,"d/dx |u|=u du/dx/|u|");
return 0;
}
/*__________________________________________________________________*/
MEXPORT_TRIGCALC int difeqn(term t, term arg, term *next, char *reason)
/* take derivative of equation with respect to varlist[eigenvariable] */
/* get f'(x) from f(x), but dV/dt from V */
{ term left,right,temp;
int problemtype = get_problemtype();
if(FUNCTOR(t) != '=')
return 1;
if(SOLVETYPE(problemtype) &&
problemtype != IMPLICIT_DIFF &&
problemtype != RELATED_RATES
)
{ errbuf(0, english(608));
/* Can't differentiate while solving equations. */
errbuf(1, english(609));
/* Example: solve x = 1; dx/dx = 1 = d1/dx = 0 */
/* but: it's ok in IMPLICIT_DIFF because the equation is
still universal with respect to x */
}
if(problemtype == RELATED_RATES && contains(t,DIFF))
{ errbuf(0, english(1922));
/* You have already differentiated the equation. */
return 1;
}
left = ARG(0,t);
right = ARG(1,t);
arg = get_eigenvariable();
*next = equation(dif_aux2(left,arg),dif_aux2(right,arg));
HIGHLIGHT(*next);
strcpy(reason,"u=v => du/dt = dv/dt");
if(isascii(FUNCTOR(arg)))
{ char c = (char) FUNCTOR(arg);
reason[11] = reason[19] = c;
}
if(problemtype == RELATED_RATES)
{ copy(t,&temp);
PROTECT(temp);
*next = and(temp, *next); /* Keep the original equation too */
}
return 0;
}
/*__________________________________________________________________*/
MEXPORT_TRIGCALC int difdif(term t, term arg, term *next, char *reason)
/* d^2u/dx^2 = (d/dx)(du/dx) etc. */
{ term u,x,n;
if(FUNCTOR(t) != DIFF || ARITY(t) != 3)
return 1;
u = ARG(0,t);
n = ARG(2,t);
x = ARG(1,t);
if(!equals(n,two))
return 1;
*next = diff(diff(u,x),x);
strcpy(reason,"$d^2u/dx^2 = (d/dx)(du/dx)$");
SETCOLOR(*next,YELLOW);
return 0;
}
/*__________________________________________________________________*/
MEXPORT_TRIGCALC int difdifn(term t, term arg, term *next, char *reason)
/* d^2u/dx^2 = (d/dx)(du/dx) etc. */
{ term u,x,n,v;
int err;
int mathmode = get_mathmode();
if(FUNCTOR(t) != DIFF || ARITY(t) != 3)
return 1;
u = ARG(0,t);
n = ARG(2,t);
x = ARG(1,t);
if(equals(n,two))
return difdif(t,arg,next,reason);
err = value(n,&v);
if(err && mathmode == AUTOMODE)
return 1;
if(err && mathmode == MENUMODE)
{ err = check(lessthan(one,n));
if(!err)
v = sum(n,minusone);
else
return 1;
}
*next = diff(diff3(u,x,v),x);
SETCOLOR(*next,YELLOW);
strcpy(reason, english(610)); /* definition of d�u/dx� */
return 0;
}
/*__________________________________________________________________*/
MEXPORT_TRIGCALC int derivop(term t, term arg, term *next, char *reason)
/* take derivative in one step */
{ if(FUNCTOR(t)!= DIFF)
return 1;
if(ARITY(t) != 2)
return 1;
if(equals(ARG(0,t),ARG(1,t)))
{ SetShowStepOperation(difidentity);
return difidentity(t,arg,next,reason);
}
if(!depends(ARG(0,t),ARG(1,t)))
{ SetShowStepOperation(difconstant);
return difconstant(t,arg,next,reason);
}
*next = derivative(ARG(0,t),ARG(1,t));
if(equals(*next,t))
return 1; /* dy/dx in, dy/dx out; nothing done */
SETCOLOR(*next,YELLOW);
strcpy(reason, english(611)); /* calculate derivative */
return 0;
}
/*_______________________________________________________________________*/
MEXPORT_TRIGCALC int difpoly(term t, term arg, term *next, char *reason)
/* Differentiate a polynomial all at once */
/* Also differentiate all monomials in a sum such as x + 3x^2 + sin x + x^4 */
{ term x,u,v,c,s;
unsigned short n;
int i;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(equals(u,x))
{ SetShowStepOperation(difidentity);
return difidentity(t,arg,next,reason);
}
if(!depends(u,x))
{ SetShowStepOperation(difconstant);
return difconstant(t,arg,next,reason);
}
if((FUNCTOR(u) == '*' || FRACTION(u)) && !monomial(u))
{ /* it still should work on cx */
twoparts(u,x,&c,&s);
if(equals(s,x))
{ *next = c;
HIGHLIGHT(*next);
strcpy(reason, english(657));
return 0;
}
if(monomial(s))
{ *next = product(c,derivative(s,x));
HIGHLIGHT(*next);
strcpy(reason,english(657));
return 0;
}
return 1;
}
if(mvpoly(u))
*next = derivative(u,x);
else if(FUNCTOR(u) != '+')
return 1;
else /* e.g. x + 3x^2 + sin x + x^4 */
{ n = ARITY(u);
*next = make_term('+',n);
for(i=0;i<n;i++)
{ v = ARG(i,u);
if(monomial(v))
ARGREP(*next,i,derivative(v,x));
else if(FRACTION(v) || FUNCTOR(v) == '*')
{ twoparts(v,x,&c,&s);
if(equals(s,x))
ARGREP(*next,i,c);
else if(monomial(s))
ARGREP(*next,i,product(c,derivative(s,x)));
else
ARGREP(*next,i,product(c,diff(s,x)));
}
else
ARGREP(*next,i,diff(v,x));
}
}
HIGHLIGHT(*next);
strcpy(reason, english(657));
/* differentiate polynomial */
/* so they can see what menu operator was used */
return 0;
}
/*_____________________________________________________________*/
static term dif_aux2(term u, term x)
/* x is an atom. Return diff(u,x) unless u is already a derivative
and then return a higher-derivative term, one higher derivative than u.
However, unlike dif_aux in maketerm.c, if u is a number or an
atom not depending on x, return zero.
*/
{ term v,index,ans;
int err;
unsigned f = FUNCTOR(u);
if(f == PR && equals(x,get_eigenvariable()))
{ v = sum(ARG(1,u),one);
err = value(v,&index);
if(err==1)
index = v;
ans = make_term(PR,2);
ARGREP(ans,0,ARG(0,u));
ARGREP(ans,1,index);
return ans;
}
if(!ATOMIC(u) && !PREDEFINED_FUNCTOR(f))
{ /* differentiate f(x) to f'(x) */
ans = make_term(PR,2);
ARGREP(ans,0,u);
ARGREP(ans,1,one);
return ans;
}
if(f != DIFF)
{ if(ISATOM(u) && !depends(u,x))
return zero;
if(seminumerical(u))
return zero;
return diff(u,x);
}
if(!equals(x,ARITY(u)==2 ? ARG(1,u) : ARG(2,u)))
return diff(u,x);
if(ARITY(u) == 2)
return diff3(ARG(0,u),x,two);
v = sum(ARG(1,u),one);
err = value(v,&index);
if(err==1)
index = v;
return diff3(ARG(0,u),x,index);
}
/*_______________________________________________________________*/
MEXPORT_TRIGCALC int diflncos(term t, term arg, term *next, char *reason)
/* d/dx ln(cos x) = -tan x */
{ term u,x;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
if(FUNCTOR(ARG(0,t)) != LN)
return 1;
if(FUNCTOR(ARG(0,ARG(0,t))) != COS)
return 1;
x = ARG(1,t);
u = ARG(0,ARG(0,ARG(0,t)));
if(equals(u,x))
*next = tnegate(tan1(x));
else
*next = tnegate(product(tan1(u), diff(u,x)));
HIGHLIGHT(*next);
strcpy(reason,"d/dx ln(cos x)=-tan x");
return 0;
}
/*_______________________________________________________________*/
MEXPORT_TRIGCALC int diflnsin(term t, term arg, term *next, char *reason)
/* d/dx ln(sin x) = cot x */
{ term u,x;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
if(FUNCTOR(ARG(0,t)) != LN)
return 1;
if(FUNCTOR(ARG(0,ARG(0,t))) != SIN)
return 1;
x = ARG(1,t);
u = ARG(0,ARG(0,ARG(0,t)));
if(equals(u,x))
*next = cot1(x);
else
*next = product(cot1(u), diff(u,x));
HIGHLIGHT(*next);
strcpy(reason,"d/dx ln(sin x)=cot x");
return 0;
}
/*_______________________________________________________________*/
MEXPORT_TRIGCALC int diflncosh(term t, term arg, term *next, char *reason)
/* d/dx ln(cosh x) = tanh x */
{ term u,x;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
if(FUNCTOR(ARG(0,t)) != LN)
return 1;
if(FUNCTOR(ARG(0,ARG(0,t))) != COSH)
return 1;
x = ARG(1,t);
u = ARG(0,ARG(0,ARG(0,t)));
if(equals(u,x))
*next = tanh1(x);
else
*next = product(tanh1(u), diff(u,x));
HIGHLIGHT(*next);
strcpy(reason,"d/dx ln(cosh x)=-tanh x");
return 0;
}
/*_______________________________________________________________*/
MEXPORT_TRIGCALC int diflnsinh(term t, term arg, term *next, char *reason)
/* d/dx ln(sinh x) = coth x */
{ term u,x;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
if(FUNCTOR(ARG(0,t)) != LN)
return 1;
if(FUNCTOR(ARG(0,ARG(0,t))) != SINH)
return 1;
x = ARG(1,t);
u = ARG(0,ARG(0,ARG(0,t)));
if(equals(u,x))
*next = coth1(x);
else
*next = product(coth1(u), diff(u,x));
HIGHLIGHT(*next);
strcpy(reason,"d/dx ln(sinh x)=coth x");
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists