Differentiating code – addendum

This post describes how to the compute derivatives mentioned in an earlier post using Maxima, a computer algebra system. Code is listed in a monospaced font and answers are written directly below, in LaTeX. Ending lines with dollar signs in Maxima (instead of semicolons) surpresses the output, which is very useful for definitions.

Start by defining the reflectance model.

U: c_0 * lambda^2 + c_1 * lambda + c_2$
R: 1 / 2 + U / (2 * sqrt(1 + U^2))$

Differentiate R with respect to c_0. The expansion of U appears a few times in the result. Substitute U_ for U to simplify it. (The underscore is there so it doesn't expand back to the full expression.)

diff(R, c_0)$
subst(U_, U, %);

$$\frac{\mathrm{d}R}{\mathrm{d}c_0} = \frac{\lambda^2}{2\sqrt{U^2+1}} - \frac{U^2\lambda^2}{2(U^2+1)^\frac{3}{2}}}$$

This can be further simplified by substituting $t_1 = \sqrt{U^2 + 1}$. Unfortunately subst won't recognize $(U^2 + 1)^\frac{3}{2}$ as $t_1^3$ so I recommend doing this manually.

$$\frac{\mathrm{d}R}{\mathrm{d}c_0} = \frac{\lambda^2}{2t_1} - \frac{U^2\lambda^2}{2t_1^3}$$

Repeating the process for the other coefficients reveals a pattern. Let $t_2 = \frac{1}{2t_1} - \frac{U^2}{2t_1^3}$.

  \frac{\mathrm{d}R}{\mathrm{d}c_0} = \lambda^2 t_2 \\
  \frac{\mathrm{d}R}{\mathrm{d}c_1} = \lambda t_2 \\
  \frac{\mathrm{d}R}{\mathrm{d}c_2} = t_2

After skipping trivial derivatives, which can be easily done by hand, one will find themselves having to differentiate the final expression for $\Delta E$. Normally an expression like $\frac{\mathrm{d}L}{\mathrm{d}c_0}$ (diff(L, c_0)) would be treated as a derivative of a constant in Maxima and reduced to zero. One can use depends to tell the program that the L*a*b* coordinates are functions of the model parameters. The result will then contain derivatives of the coordinates themselves.

An alternative approach is typing out the coordinates as functions explicitly. Instead of using depends, replace L with L(c_0, c_1, c_2) (and so on for a and b) in the code below. The downside is that the function arguments will appear in the end result, cluttering it and making a mess.

depends([L, a, b], [c_0, c_1, c_2])$
delta_E: sqrt((L - L_target)^2 + (a - a_target)^2 + (b - b_target)^2)$

Use the same subst trick as before to simplify.

diff(delta_E, c_0)$
subst(delta_E_, delta_E, %);

$$\frac{\big(b - b_\text{target}\big)\frac{\mathrm{d}b}{\mathrm{d}c_0} + \big(a - a_\text{target}\big)\frac{\mathrm{d}a}{\mathrm{d}c_0} +\big(L - L_\text{target}\big)\frac{\mathrm{d}L}{\mathrm{d}c_0}}{\Delta E}$$

The other derivatives look the same. Simply substitute $c_1$ or $c_2$ for $c_0$ in the expression above to get obtain them.