Open sritchie opened 3 years ago
I've thought about this more, and I see now that this will only work if you call D on a function that takes a single numerical (or symbolic) argument.
The reason is that we interpret a structure of functions (up f1, f2, f3) from a => b as a single function of a => (up b1, b2, b3).
If "a" is a structure, say, (up x y z), then D needs to add a NEW structure (with orientations flipped) around the outputs.
The correct result is
(down (up (((partial 0) f1) (up x y z))
(((partial 0) f2) (up x y z))
(((partial 0) f3) (up x y z)))
(up (((partial 1) f1) (up x y z))
(((partial 1) f2) (up x y z))
(((partial 1) f3) (up x y z)))
(up (((partial 2) f1) (up x y z))
(((partial 2) f2) (up x y z))
(((partial 2) f3) (up x y z))))
my suggestion would give:
(up (down (((partial 0) f1) (up x y z))
(((partial 1) f1) (up x y z))
(((partial 2) f1) (up x y z)))
(down (((partial 0) f2) (up x y z))
(((partial 1) f2) (up x y z))
(((partial 2) f2) (up x y z)))
(down (((partial 0) f3) (up x y z))
(((partial 1) f3) (up x y z))
(((partial 2) f3) (up x y z))))
They would match for a single numerical (or symbolic) argument.
Preserving a power series through a derivative is still something we want, I think! Maybe this hints that "partial-derivative" and "jacobian" should be two distinct generic functions.
This implies that maybe we should treat these cases separately, EVEN if they're both covered by D
...
The current implementation of
g/partial-derivative
for::s/structure
instances is the same implementation used by::function
.The reason for this, I think (and the reason it works!) Is that all of the machinery that
derivative.cljc
develops to allow for structured inputs (Jacobian support) gets to work a SINGLE time and call the structure as a function for each perturbed input in the incoming structure.The alternative would be to implement
partial-derivative
on structures like this:This would fix two problems I've noticed:
PowerSeries
, or really any structure whose derivative we can take cheaply WITHOUT callingderivative
and using forward-mode AD, we currently always bypass that implementation. aPowerSeries
in particular can take its own derivative easily, and would stay aPowerSeries
. The current implementation actually calls it, dropping it back down toSeries
(and not appropriately shifting all of the entries!!)IPersistentVector
that you haven't turned into a structure, the whole current approach will fail because a vector implementsIFn
by looking up an entry, no applying its args to contained functions.Compare these two cases for an example: