Hello
I've made a little progress today.
I made a little program (
https://raw.github.com/bl0ckeduser/sympy/master/test.py) that tracks
the stack frames of all calls to _eval_derivative and prints out their inputs and outputs,
as the Wiki suggested.
The output for that exact task looks something like this:
Expression : cos(log(sqrt(a))
Differentiating w.r.t. a:
d/d( a ) [ a ] = 1
d/d( a ) [ sqrt(a) ] = 1/(2*sqrt(a))
d/d( a ) [ log(sqrt(a)) ] = 1/(2*a)
d/d( a ) [ cos(log(sqrt(a))) ] = -sin(log(sqrt(a)))/(2*a)
This does what the wiki suggests, but it is not exactly clear
how consecutive steps relate to each other. Of course, this is not
the exact desired behaviour, as found in programs like Wolfram.
So I took things further by writing a little loop that looks for exact
substitutions between steps to try to write a full "step-by-step" solution
showing the original full expression as it evolves after every call to the derivative routine.
Unfortunately this doesn't work very well for many expressions because
there is some kind of simplification code being called somewhere that kills
exact substitutions, for example [ 1/(2*a) ] in one step gets multiplied
by [ -sin(log(sqrt(a))) ] in the next step, but it is not possible to see
the exact earlier node [ 1/(2*a) ] in the resulting expression [ -sin(log(sqrt(a)))/(2*a) ].
Perhaps there is some flag somewhere to recursively disable simplifications ?
Below is one case (with output slightly reformatted from my test program)
where this hacky loop did work relatively well:
D(cos(log(a**5) + sin(a))**2, a)
= -2 * D(log(a**5) + sin(a), a) * sin(log(a**5) + sin(a)) * cos(log(a**5) + sin(a))
= -2 * ( D(log(a**5), a) + D(sin(a), a) ) * sin(log(a**5) + sin(a)) * cos(log(a**5) + sin(a))
= -2*(cos(a) + 5/a) * sin(log(a**5) + sin(a)) * cos(log(a**5) + sin(a))
A combined chain and power rule is somewhat visible in the first two lines,
and a sum rule / linear distribution of differentiation is visible the second.
In the last step, cos(a) and log(a**5) are both differentiated.
I suspect another possible approach would be to somehow modify the code
so that it first outputs purely symbolic, not actually evaluated or applied, differentiation
nodes, displays them, and then proceeds to evaluate them.
I'm still quite unsure whether the overall task is approachable or not.
Best,
Bl0ckeduser