Sindbad~EG File Manager
/* Differentiation of transcendentals, operators for MathXpert
M. Beeson
9.10.91 original date
3.19.98 last modified
10.13.10 modified difexp2 to work more explicitly when the topic is chainrule
2.5.24 $$ reasons throughout
5.8.24 corrected secondderiv at line 477 and highderiv at line 500
5.11.24 corrected two reason strings
*/
#include <string.h>
#include <assert.h>
#include "globals.h"
#include "ops.h"
#include "trig.h"
#include "calc.h"
#include "checkarg.h"
#include "polynoms.h"
#include "order.h"
#include "factor.h"
#include "deriv.h"
#include "prover.h"
#include "algaux.h"
#include "errbuf.h"
#include "pvalaux.h" /* twoparts */
#include "cflags.h" /* get_currenttopic */
#include "tdefn.h"
/*______________________________________________________________________*/
static void set_chainrule_errmsg(void)
/* See diff.c. This is a static copy to avoid swapping overlays
just to get this short function.
*/
{ errbuf(0, english(593));
errbuf(1, english(594));
errbuf(2, english(595));
errbuf(3, english(596));
}
/*_______________________________________________________________________*/
int difsin(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != SIN)
return 1;
if(!equals(ARG(0,u),x))
{ set_chainrule_errmsg();
return 1;
}
*next = cos1(x);
HIGHLIGHT(*next);
strcpy(reason,"$$diff(sin x,x) = cos(x)$$");
return 0;
}
/*_______________________________________________________________________*/
int difsin2(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != SIN)
return 1;
p = ARG(0,u);
if(equals(p,x))
{ *next = cos1(x);
strcpy(reason,"$$diff(sin x,x) = cos(x)$$");
}
else
{ *next = product(cos1(p),diff(p,x));
strcpy(reason,"$$diff(sin(u),x) = (cos u) diff(u,x)$$");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int difcos(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != COS)
return 1;
if(!equals(ARG(0,u),x))
{ set_chainrule_errmsg();
return 1;
}
*next = tnegate(sin1(x));
HIGHLIGHT(*next);
strcpy(reason,"$$diff(cos(x),x) = - sin(x)$$");
return 0;
}
/*_______________________________________________________________________*/
int difcos2(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != COS)
return 1;
p = ARG(0,u);
if(equals(p,x))
{ *next = tnegate(sin1(x));
strcpy(reason,"$$diff(cos(x),x) = - sin(x)$$");
}
else
{ *next = tnegate(product(sin1(p),diff(p,x)));
strcpy(reason,"$$diff(cos(u),x) = - sin(u) diff(u,x)$$");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int diftan(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != TAN)
return 1;
if(!equals(ARG(0,u),x))
{ set_chainrule_errmsg();
return 1;
}
*next = make_power(sec1(x),two);
HIGHLIGHT(*next);
strcpy(reason,"$$ diff(tan x,x) = sec^2 x$$");
return 0;
}
/*_______________________________________________________________________*/
int diftan2(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != TAN)
return 1;
p = ARG(0,u);
if(equals(p,x))
{ *next = make_power(sec1(x),two);
strcpy(reason,"$$ diff(tan x,x) = sec^2 x$$");
}
else
{ *next = product(make_power(sec1(p),two),diff(p,x));
strcpy(reason,"$$ diff(tan u,x) = sec^2 u diff(u,x)$$");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int difsec(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != SEC)
return 1;
if(!equals(ARG(0,u),x))
{ set_chainrule_errmsg();
return 1;
}
*next = product(sec1(x),tan1(x));
HIGHLIGHT(*next);
strcpy(reason,"$$ diff(sec x,x) = sec x tan x$$");
return 0;
}
/*_______________________________________________________________________*/
int difsec2(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != SEC)
return 1;
p = ARG(0,u);
if(equals(p,x))
{ *next = product(sec1(x),tan1(x));
strcpy(reason,"$$ diff(sec x,x) = sec x tan x$$");
}
else
{ *next = product3(sec1(p),tan1(p),diff(p,x));
strcpy(reason,"$$ diff(sec u,x) = sec u tan u diff(u,x)$$");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int difcot(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != COT)
return 1;
if(!equals(ARG(0,u),x))
{ set_chainrule_errmsg();
return 1;
}
*next = tnegate(make_power(csc1(x),two));
HIGHLIGHT(*next);
strcpy(reason,"$$diff(cot x,x) = -csc^2 x$$");
return 0;
}
/*_______________________________________________________________________*/
int difcot2(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != COT)
return 1;
p = ARG(0,u);
if(equals(p,x))
{ *next = tnegate(make_power(csc1(x),two));
strcpy(reason,"$$diff(cot x,x) = -csc^2 x$$");
}
else
{ *next = tnegate(product(make_power(csc1(p),two),diff(p,x)));
strcpy(reason,"$$diff(cot u,x) = -csc^2 u diff(u,x)$$");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int difcsc(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != CSC)
return 1;
if(!equals(ARG(0,u),x))
{ set_chainrule_errmsg();
return 1;
}
*next = tnegate(product(csc1(x),cot1(x)));
HIGHLIGHT(*next);
strcpy(reason,"$$diff(csc x,x) = - csc x cot x$$");
return 0;
}
/*_______________________________________________________________________*/
int difcsc2(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != CSC)
return 1;
p = ARG(0,u);
if(equals(p,x))
{ *next = tnegate(product(csc1(x),cot1(x)));
strcpy(reason,"$$diff(csc x,x) = - csc x cot x$$");
}
else
{ *next = tnegate(product3(csc1(p),cot1(p),diff(p,x)));
strcpy(reason,"$$diff(csc u,x) = - csc u cot u diff(u,x)$$");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int difatox(term t, term arg, term *next, char *reason)
/* d/dx a^x = (ln a) a^x if a doesn't depend on x */
{ term x,a,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
if(FUNCTOR(ARG(0,t)) != '^')
return 1;
u = ARG(1,ARG(0,t));
a = ARG(0,ARG(0,t));
if(!equals(u,x))
{ set_chainrule_errmsg();
return 1;
}
if(depends(a,x))
{ errbuf(0, english(650)); /* Base is not constant. */
errbuf(1, english(651));
/* Use d/dx u^v = (d/dx) e^(v ln u) instead. */
return 1;
}
*next = product(ln1(a),ARG(0,t));
HIGHLIGHT(*next);
strcpy(reason,"$$ diff(a^x,x) d/dx a^x = (ln a) a^x$$");
return 0;
}
/*_______________________________________________________________________*/
int difatox2(term t, term arg, term *next, char *reason)
/* d/dx a^u = (ln a) a^u du/dx if a doesn't depend on x */
{ term x,a,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
if(FUNCTOR(ARG(0,t)) != '^')
return 1;
u = ARG(1,ARG(0,t));
a = ARG(0,ARG(0,t));
if(depends(a,x))
{ errbuf(0, english(650)); /* Base is not constant. */
errbuf(1, english(651));
/* Use d/dx u^v= (d/dx) e^(v ln u) instead. */
return 1;
}
*next = product3(ln1(a),ARG(0,t),diff(u,x));
HIGHLIGHT(*next);
strcpy(reason,"$$ diff(a^u,x) = (ln a) a^u diff(u,x)$$");
return 0;
}
/*_______________________________________________________________________*/
int difln(term t, term arg, term *next, char *reason)
{ term x,u,v;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != LN)
return 1;
v = FUNCTOR(ARG(0,u))==ABSFUNCTOR ? ARG(0,ARG(0,u)) : ARG(0,u);
if(!equals(v,x))
{ set_chainrule_errmsg();
return 1;
}
*next = make_fraction(one,v);
HIGHLIGHT(*next);
if(FUNCTOR(ARG(0,u))==ABSFUNCTOR)
strcpy(reason, "$$diff(ln (abs(x)) ,x) = 1/x$$");
else
strcpy(reason,"$$diff(ln x,x) = 1/x$$");
return 0;
}
/*_______________________________________________________________________*/
int diflnabs(term t, term arg, term *next, char *reason)
/* d/dx ln |x| = 1/x */
{ term x,u,v;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != LN)
return 1;
if(FUNCTOR(ARG(0,u)) != ABSFUNCTOR)
return 1;
v = ARG(0,ARG(0,u));
if(!equals(v,x))
{ set_chainrule_errmsg();
return 1;
}
*next = make_fraction(one,v);
HIGHLIGHT(*next);
strcpy(reason, "$$diff(ln (abs(x)),x) = 1/x$$");
return 0;
}
/*_______________________________________________________________________*/
int difln2(term t, term arg, term *next, char *reason)
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != LN)
return 1;
p = ARG(0,u);
if(FUNCTOR(p)==ABSFUNCTOR)
p = ARG(0,p);
if(equals(p,x))
return difln(t,arg,next,reason);
else
{ *next = make_fraction(diff(p,x),p);
if(FUNCTOR(ARG(0,u))==ABSFUNCTOR)
strcpy(reason,"d/dx ln |u|=(du/dx)/x");
else
strcpy(reason,"d/dx ln u = (du/dx)/x");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int diflnabs2(term t, term arg, term *next, char *reason)
/* d/dx ln |u|=(du/dx)/x */
{ term x,u,p;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != LN)
return 1;
p = ARG(0,u);
if(FUNCTOR(p)!=ABSFUNCTOR)
return 1;
p = ARG(0,p);
if(equals(p,x))
return diflnabs(t,arg,next,reason);
else
{ *next = make_fraction(diff(p,x),p);
strcpy(reason,"d/dx ln |u|=(du/dx)/x");
}
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int difexponential(term t, term arg, term *next, char *reason)
/* d/dx (u^v) = d/dx e^(v ln u) */
{ term x,q,u,v,power;
int err;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
q = ARG(0,t);
if(FUNCTOR(q) != '^')
return 1;
u = ARG(0,q);
v = ARG(1,q);
if(!depends(v,x))
{ errbuf(0, english(652)); /* The exponent is constant, */
errbuf(1, english(653)); /* So use the power rule instead. */
return 1;
}
err = check1(positive(u));
if(err)
{ errbuf(0, english(654));
/* Can't take ln of a negative number. */
return 1;
}
power = product(v,ln1(u));
if(FUNCTOR(power)=='*')
sortargs(power);
*next = diff(make_power(eulere,power),x);
strcpy(reason,"$$u^v = e^(v ln u)$$");
HIGHLIGHT(ARG(0,*next));
inhibit(lninexponent); /* released when the derivative is evaluated */
return 0;
}
/*_______________________________________________________________________*/
int secondderivlinear(term t, term arg, term *next, char *reason)
/* (AX)" = A X" and etc. for higher derivs */
{ term x,u,c,v,n;
if(FUNCTOR(t) != DIFF || ARITY(t) != 3)
return 1;
x = ARG(1,t);
u = ARG(0,t);
n = ARG(2,t);
if(FUNCTOR(u) != '*')
return 1;
twoparts(u,x,&c,&v);
if(ONE(c))
return 1;
*next = product(c,diff3(v,x,n));
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int secondderiv(term t, term arg, term *next, char *reason)
/* deriv of deriv is second deriv */
{ term x,u,v;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) != DIFF || ARITY(u) != 2)
return 1;
if(!equals(ARG(1,u),x))
{errbuf(0, english(655));
/* The two derivatives must be with */
errbuf(1, english(656));
/* respect to the same variable. */
}
v = ARG(0,u);
*next = diff3(v,x,two);
strcpy(reason,"$$diff(diff(u,x),x) = diff(u,x,2)$$");
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int highderiv(term t, term arg, term *next, char *reason)
/* deriv of n-th deriv is n+1-st deriv */
{ term x,u,v,n,m,k;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
k = ARITY(t)==2 ? one : ARG(2,t);
if(FUNCTOR(u) != DIFF || ARITY(u) == 2)
return 1;
if(!equals(ARG(1,u),x))
{ errbuf(0, english(655));
/* The two derivatives must be with */
errbuf(1, english(656));
/* respect to the same variable. */
}
v = ARG(0,u);
m = ARG(2,u);;
polyval(sum(k,m),&n);
*next = diff3(v,x,n);
if(equals(k,one) )
strcpy(reason,"$$diff(diff(u,x,n),x) = diff(u,x,n+1)$$");
else
// strcpy(reason,"$d^m/dx^m(d^n u/dx^n)$ = d^(m+n)u/dx^(m+n)");
strcpy(reason,"$$diff(diff(u,x,n),x,m) = diff(u,x,m+n)$$");
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________________*/
int reversesecondderiv(term t, term arg, term *next, char *reason)
/* second deriv is deriv of deriv */
/* or n+1-st deriv is deriv of n-th deriv */
{ term x,u,n,new;
int err;
if(FUNCTOR(t) != DIFF || ARITY(t) != 3)
return 1;
x = ARG(1,t);
u = ARG(0,t);
n = ARG(2,t);
polyval(sum(n,minusone),&new);
/* No need to check that n is an integer as non-integers can never
get created in this arg position of diff */
if(ONE(new))
{ *next = diff(u,x);
strcpy(reason, "$$diff(u,x,2) = diff(diff(u,x),x)$$");
HIGHLIGHT(*next);
return 0;
}
if (!INTEGERP(new))
{ err = check1(le(zero,new));
if(err)
return 1; /* I don't think this can ever happen */
}
*next = diff3(u,x,new);
strcpy(reason,english(2168)); /* defn of d^nu/dx^n */
HIGHLIGHT(*next);
return 0;
}
/*____________________________________________________________________*/
static void difvector_aux(term u, term x, unsigned short n, term *next)
/* differentiate vector u of length n term-by-term with respect to x
and return the answer in *next */
{ int i;
term v;
*next = make_term(VECTOR,n);
for(i=0;i<n;i++)
{v = ARG(i,u);
if(ZERO(v) || !depends(v,x))
ARGREP(*next,i,zero);
else
ARGREP(*next,i,diff(ARG(i,u),x));
}
}
/*____________________________________________________________________*/
int difvector(term t, term arg, term *next, char *reason)
/* d/dx {u,v...} = {du/dx,dv/dx...} */
{ unsigned short n;
term u,x;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
u = ARG(0,t);
x = ARG(1,t);
if(FUNCTOR(u) != VECTOR)
return 1;
n = ARITY(t);
difvector_aux(u,x,n,next);
HIGHLIGHT(*next);
if(n==2)
strcpy(reason, "d/dx {u,v} = {du/dx,dv/dx}");
else if(n==3)
strcpy(reason, "d/dx {u,v,w} = {du/dx,dv/dx,dw/dx}");
else
strcpy(reason, "d/dx {u,v,...} = {du/dx,dv/dx,...}");
return 0;
}
/*____________________________________________________________________*/
int difmatrix(term t, term arg, term *next, char *reason)
/* d/dx {u,v...} = {du/dx,dv/dx...} */
{ unsigned short n;
term u,x,v;
int i;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
u = ARG(0,t);
x = ARG(1,t);
if(FUNCTOR(u) != MATRIX)
return 1;
n = ARITY(t);
*next = make_term(MATRIX,n);
for(i=0;i<n;i++)
{v = ARG(i,u);
difvector_aux(v,x,n,ARGPTR(*next)+i);
}
HIGHLIGHT(*next);
strcpy(reason, english(2169)); /* differentiate matrix */
return 0;
}
/*_________________________________________________________________*/
int logdif(term t, term arg, term *next, char *reason)
/* logarithmic differentiation dy/dx = y (d/dx) ln y */
{ term y,x;
if(FUNCTOR(t) != DIFF || ARITY(t) != 2)
return 1;
y = ARG(0,t);
x = ARG(1,t);
*next = product(y,diff(ln1(y),x));
HIGHLIGHT(*next);
strcpy(reason, "$$diff(y,x) = y diff(ln y, x)$$");
return 0;
}
/*_______________________________________________________________________*/
int difexp(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) == '^' && equals(ARG(0,u),eulere))
{if(!equals(ARG(1,u),x))
{ set_chainrule_errmsg();
return 1;
}
}
else
return 1; /* wrong functor for this rule */
*next = u;
HIGHLIGHT(*next);
strcpy(reason, "$$diff(e^x,x)= e^x$$");
return 0;
}
/*_______________________________________________________________________*/
int difexp2(term t, term arg, term *next, char *reason)
{ term x,u;
if(FUNCTOR(t) != DIFF)
return 1;
x = ARG(1,t);
u = ARG(0,t);
if(FUNCTOR(u) == '^' && equals(ARG(0,u),eulere))
{ if(ispolyin(ARG(1,u),x))
{ if (status(difpoly) > LEARNING && get_currenttopic() != _chain_rule)
*next = product(u,derivative(ARG(1,u),x));
else
*next = product(u,diff(ARG(1,u),x));
}
else
*next = product(u,diff(ARG(1,u),x));
strcpy(reason,"$$ diff(e^u,x) = e^u diff(u,x)$$");
if(contains(ARG(1,u),LN))
release(lninexponent);
}
else
return 1;
HIGHLIGHT(*next);
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists