lec18.mws

L-18 MCS 320 Monday 3 October 2005

> restart;

1. Symbolic Differentiation

Symbolic differentiation is done by the "diff" command, and the inert version "Diff".  This is the derivation of formulas, as we do on paper.

> expsin := exp(sin(x));

expsin := exp(sin(x))

> Diff(expsin,x) = diff(expsin,x);

Diff(exp(sin(x)), x) = cos(x)*exp(sin(x))

The "Diff" only stores the definition of a derivative, while "diff" executes.

> T := op(diff)

T := proc () options builtin, remember; table( [( sin(x), x ) = cos(x), ( exp(sin(x)), x ) = cos(x)*exp(sin(x)) ] ) 176 end proc

> ;

> T := op(4,eval(diff

T := TABLE([(sin(x), x) = cos(x), (exp(sin(x)), x) = cos(x)*exp(sin(x))])

> ));

We see how Maple stores the results of previous calls.  Here we change the remember table:

> T[(sin(x),x)] := sin(x);

T[sin(x), x] := sin(x)

> diff(sin(x),x);  # intended effec

sin(x)

> t

> forget(diff);

> diff(sin(x),x);

cos(x)

Often the formulas we want to define are implicitly defined by an equation.

Suppose we would like to compute the tangent line to a circle, given as x^2 + y^2 - 1= 0, at some point.  We could solve for y, write y as a function of x.  But we should actually consider y as a function of x and derive the equation.

> alias(y=y(x));  # see y not as the symbol y, but as function of x

y

> diff(y,x);

diff(y, x)

Without the alias, diff(y,x) would have returned zero.  We now consider the equation for the circle:

> circle := x^2 + y^2 = 1;

circle := x^2+y^2 = 1

> equ := diff(circle,x);

equ := 2*x+2*y*diff(y, x) = 0

> solve(equ,diff(y,x));

-x/y

The short way to compute the derivative of a formula defined by implicitly by an equation is

> implicitdiff(x^2 + z^2=1,z,x);

-x/z

Here we choose z as second variable, because y = y(x).  With implicitdiff, we do not need to use an alias.  We just take the equation as first argument.

> x$10;  # the $ operator creates sequences

x, x, x, x, x, x, x, x, x, x

to be used for repeated differentiation, say the 10-th derivative:

> diff(expsin,x$10);

-120*cos(x)^8*exp(sin(x))+256*cos(x)^2*exp(sin(x))+25515*sin(x)^2*cos(x)^2*exp(sin(x))-19530*sin(x)*cos(x)^4*exp(sin(x))-sin(x)*exp(sin(x))-255*sin(x)^2*exp(sin(x))+7125*sin(x)*cos(x)^2*exp(sin(x))-54...-120*cos(x)^8*exp(sin(x))+256*cos(x)^2*exp(sin(x))+25515*sin(x)^2*cos(x)^2*exp(sin(x))-19530*sin(x)*cos(x)^4*exp(sin(x))-sin(x)*exp(sin(x))-255*sin(x)^2*exp(sin(x))+7125*sin(x)*cos(x)^2*exp(sin(x))-54...-120*cos(x)^8*exp(sin(x))+256*cos(x)^2*exp(sin(x))+25515*sin(x)^2*cos(x)^2*exp(sin(x))-19530*sin(x)*cos(x)^4*exp(sin(x))-sin(x)*exp(sin(x))-255*sin(x)^2*exp(sin(x))+7125*sin(x)*cos(x)^2*exp(sin(x))-54...-120*cos(x)^8*exp(sin(x))+256*cos(x)^2*exp(sin(x))+25515*sin(x)^2*cos(x)^2*exp(sin(x))-19530*sin(x)*cos(x)^4*exp(sin(x))-sin(x)*exp(sin(x))-255*sin(x)^2*exp(sin(x))+7125*sin(x)*cos(x)^2*exp(sin(x))-54...

> implicitdiff(x^2+z^2=1,z,x$10);  # to get the 10-th derivative

-14175*(7*z^10+315*x^2*z^8+6435*x^8*z^2+6006*x^6*z^4+2310*x^4*z^6+2431*x^10)/z^19

2. Automatic Differentation

Automatic differentation is the differentation of procedures.  Typically this is done by the command "D", although the quiz 6 with piecewise is also an example of automatic differentiation.

The result of automatic differentiation is again a procedure:

> f := unapply(expsin,x);

f := `@`(exp, proc (x) options operator, arrow; sin(x) end proc)

> df := D(f);

df := `@`(exp, proc (x) options operator, arrow; sin(x) end proc)*cos

> df(1.2); df(z);

.9202736594

exp(sin(z))*cos(z)

> df10 := D[1$10](f); # 10-th derivative

df10 := 256*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*cos^2+7125*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*sin*cos^2-19530*`@`(exp, proc (x) options operator, arrow...df10 := 256*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*cos^2+7125*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*sin*cos^2-19530*`@`(exp, proc (x) options operator, arrow...df10 := 256*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*cos^2+7125*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*sin*cos^2-19530*`@`(exp, proc (x) options operator, arrow...df10 := 256*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*cos^2+7125*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*sin*cos^2-19530*`@`(exp, proc (x) options operator, arrow...df10 := 256*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*cos^2+7125*`@`(exp, proc (x) options operator, arrow; sin(x) end proc)*sin*cos^2-19530*`@`(exp, proc (x) options operator, arrow...

The [1$10] means: apply D ten times to the first variable.

> df10(x);

256*exp(sin(x))*cos(x)^2+7125*exp(sin(x))*sin(x)*cos(x)^2-19530*exp(sin(x))*sin(x)*cos(x)^4-120*exp(sin(x))*cos(x)^8+2352*exp(sin(x))*cos(x)^6-5440*exp(sin(x))*cos(x)^4+25515*exp(sin(x))*sin(x)^2*cos(...256*exp(sin(x))*cos(x)^2+7125*exp(sin(x))*sin(x)*cos(x)^2-19530*exp(sin(x))*sin(x)*cos(x)^4-120*exp(sin(x))*cos(x)^8+2352*exp(sin(x))*cos(x)^6-5440*exp(sin(x))*cos(x)^4+25515*exp(sin(x))*sin(x)^2*cos(...256*exp(sin(x))*cos(x)^2+7125*exp(sin(x))*sin(x)*cos(x)^2-19530*exp(sin(x))*sin(x)*cos(x)^4-120*exp(sin(x))*cos(x)^8+2352*exp(sin(x))*cos(x)^6-5440*exp(sin(x))*cos(x)^4+25515*exp(sin(x))*sin(x)^2*cos(...256*exp(sin(x))*cos(x)^2+7125*exp(sin(x))*sin(x)*cos(x)^2-19530*exp(sin(x))*sin(x)*cos(x)^4-120*exp(sin(x))*cos(x)^8+2352*exp(sin(x))*cos(x)^6-5440*exp(sin(x))*cos(x)^4+25515*exp(sin(x))*sin(x)^2*cos(...

This corresponds to the symbolic differentation.

Before going to an application, let us look at some notation:

> diff(cos(t),t);

-sin(t)

> diff(cos,t);

0

> D(cos(t));

D(cos(t))

> D(cos);

-sin

Only the first and the fourth command give correct results.  Notice that the first result is a formula, while the fourth result is a function.

As an application of automatic differentation, we consider a case where evaluating the derivative is easier than evaluating the symbolic expression.

> jf := z -> z^2 + 1/4;

jf := proc (z) options operator, arrow; z^2+1/4 end proc

> jf10 := jf@@10;

jf10 := `@@`(jf, 10)

> jf10(3.2);

0.7771312581e523

Applying the quadratic map 10 times with jf@@10 leads to a function which is easy to evaluate.

> sf10 := jf10(z);

sf10 := (((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4

If we begin to differentiate, we encounter expression swell:

> djf := diff(sf10,z);

djf := 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/...djf := 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/...djf := 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/...djf := 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/...

The symbolic derivative starts to get huge.

> Djf := D(jf10); # automatic differentiation

Djf := `@`(proc (z) options operator, arrow; 2*z end proc, `@@`(jf, 9))*`@`(proc (z) options operator, arrow; 2*z end proc, `@@`(jf, 8))*`@`(proc (z) options operator, arrow; 2*z end proc, `@@`(jf, 7)...

If we are only interested in the value of the derivative, i.e.: if we want to know how fast the function increase at a certain point.

> Djf(3.2);

0.2422001142e526

The alternative is to take the symbolic derivative and turn this into a procedure via the unapply.

> sdjf := unapply(djf,z);

sdjf := proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/...sdjf := proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/...sdjf := proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/...sdjf := proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/...

> eval(Djf);

`@`(proc (z) options operator, arrow; 2*z end proc, `@@`(jf, 9))*`@`(proc (z) options operator, arrow; 2*z end proc, `@@`(jf, 8))*`@`(proc (z) options operator, arrow; 2*z end proc, `@@`(jf, 7))*`@`(p...

> eval(sdjf);

proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4...proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4...proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4...proc (z) options operator, arrow; 1024*(((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*((((((((z^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)^2+1/4)*(((((((z^2+1/4)^2+1/4...

While both Djf and sdjf will give the same numbers, they are the same procedures, we see that the result of automatic differentiation is much shorter than the procedure obtained via symbolic differentiation.