Skip to main content

equation solving - How to take the derivative w.r.t. an arbitrary function?


EDIT: The answer posted by @Jens works for built-in functions only. However I'm starting to wonder if this is related to my Mathematica install somehow. I have version 7. Here is an example in the Mathematica documentation center that implies that if I ask InverseFunction[] to find the inverse of a non-built-in pure function, it will be able to. However, as a test I tried to duplicate the result:


The documentation center gives


In:= InverseFunction[(a # + b)/(c # + d) &]


Out:= (-b+d#1)/(a-c#1) &.


Using the exact same input, I get


Out:= InverseFunction[(a # + b)/(c # + d) &],


which is just the inputted command. :\



The documentation center is talking about version 9. Is there some fundamental difference in how versions 7 and 9 use InverseFunction? Is there any workaround?


I've also tried to use other definitions other than InverseFunction[], such as Solve[]...but in that case Solve[] uses inverse functions to find the solution (as evinced by the message I get:


InverseFunction::ifun: Inverse functions are being used. Values may be lost for multivalued inverses. >>


For example, following Jens's answer:


In:=InverseFunction[g][z] and


In:=q /. Solve[g[q] == z, q][[1]]


both give the same answer, $g^{(-1)}[z]$. If you replace "g" with "Log" or the head of any other built-in function, they give the same answer; for example,


In:=InverseFunction[Log][z] and


In:=q /. Solve[Log[q] == z, q][[1]]


give an answer of $e^z$, which is correct. But while the function using Solve can deal with non-built-in functions, e.g.



In:=q /. Solve[Log[q] == z, q][[1]]


Out:=10^z,


which is of course the right answer. The problem is that when trying to implement this as a workaround based on Jens's solution, it hangs up on the same error for some reason, namely that it doesn't know what do to with non-built-in functions.


Being relatively inexperienced at programming in Mathematica I'm not sure what other workarounds there may be. It also seems strange that the documentation center's example doesn't work for me, although as I say I think it's probably a version issue. Does anyone have any ideas?


_


I want to be able to take the derivative of one function (of a given variable) w.r.t. a different function (of the same variable), i.e. $\frac{df[x]}{dg[x]}$. I know you can use the chain rule to appropriately recast this into the form $\frac{dh[y]}{dy}$, where $h[y]$ is $f[x]$ evaluated at $x=g^{-1}(y)$, with $g^{-1}$ the inverse function of $g$.


There are a couple semi-related questions already posted, one of which is here, asking about how to take the derivative of the log of an arbitrary function.


I already asked a question about VariationalD (which I initially thought did what I wanted) here. I was referenced to a third question here on the Dt[] command, but I can't figure out how to get what I want from there, either.


In messing around with D[] and Dt[], I have found that, weirdly, D[] will actually do this for some special cases. For example,


In:= D[Log[x],Log[x]]



Out:= 1


and


In:= D[Log[x]^2,Log[x]]


Out:= 2Log[x].


However, commands such as D[Log[x^2],Log[x]] and D[x,Log[x]] return zero. Dt[], meanwhile, heads in the right direction, for example:


In:= Dt[Log[x^2],Log[x]]


Out:= 2 Dt[x,Log[x]]/x.


This is correct except that I don't know how to make it evaluate, even though I'm sure Mathematica can handle inverting a function to use the chain rule.


I don't want to use the logarithm function, it's just an example. I want to be able to take the derivative of a fit (with a complicated functional form) to experimental data w.r.t. different (complicated) functions. So while in principle I could hash out the equivalent derivative w.r.t. $x$, I really don't want to :)



Answer




It's just an application of the rules of differentiation, which we can implement by writing our own function:


deriv[f_, g_[x_]] := Module[{z},
Simplify[D[f /. x :> InverseFunction[g][z], z]] /. z :> g[x]
]

deriv[Log[x^2]^2, Log[x]]

(* ==> 4 Log[x^2] *)

The variable x in this call has to be undefined so it doesn't get evaluated to something unintended before the derivative with respect to Log[x] is calculated. Also, this will obviously only work if the function in the second argument actually has an inverse.



To use this deriv method with functions that don't just have a single argument as defined in the pattern above, you could first define an auxiliary function that makes the intended function conform to this pattern. E.g., for the base-10 log:


log10[x_] := Log[10, x]

deriv[Log[x^2]^2, log10[x]]

(* ==> 4 Log[10] Log[100^(Log[x]/Log[10])] *)

Edit


Since InverseFunction is less reliable in version 7, we can equally well resort to another rule of calculus and do the derivative at x this way:


Clear[deriv2];

deriv2[f_, g_, x_] := Simplify[D[f, x]/D[g, x]]

deriv2[Log[x^2]^2, Log[10, x], x]

(* ==> 4 Log[10] Log[x^2] *)

This is written without the restrictive pattern of the first definition in deriv. Instead, I allow arbitrary expressions f and g but require a third argument that spell out the independent variable x to be used in both expressions. Using FullSimplify, you can verify that this yields the same results as the previous approach when InverseFunction works, but it doesn't actually check for the invertibility of g (which should make it less likely to fail in practice).


Comments

Popular posts from this blog

plotting - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Mathematica: 3D plot based on combined 2D graphs

I have several sigmoidal fits to 3 different datasets, with mean fit predictions plus the 95% confidence limits (not symmetrical around the mean) and the actual data. I would now like to show these different 2D plots projected in 3D as in but then using proper perspective. In the link here they give some solutions to combine the plots using isometric perspective, but I would like to use proper 3 point perspective. Any thoughts? Also any way to show the mean points per time point for each series plus or minus the standard error on the mean would be cool too, either using points+vertical bars, or using spheres plus tubes. Below are some test data and the fit function I am using. Note that I am working on a logit(proportion) scale and that the final vertical scale is Log10(percentage). (* some test data *) data = Table[Null, {i, 4}]; data[[1]] = {{1, -5.8}, {2, -5.4}, {3, -0.8}, {4, -0.2}, {5, 4.6}, {1, -6.4}, {2, -5.6}, {3, -0.7}, {4, 0.04}, {5, 1.0}, {1, -6.8}, {2, -4.7}, {3, -1.