Chain Rule in R

Hi there, I just wanted to check if there is any way of having an R code that implicitly executes the chain rule during differentiation.

For example:

Given m=x^3

and b=x^2+m^2

How can I get b'=2x+6x*m?

When I use, Deriv(b) I keep getting 2x + 2m

Thanks

Hi, and welcome!

It's hard to be definite without a reprex : FAQ: What's a reproducible example (`reprex`) and how do I do one?. But this is exactly what, according to its documentation the Deriv package and its eponymous function Deriv() are supposed to do. How does your problem differ from the example?

suppressPackageStartupMessages(library(Deriv))
f <- function(x, y) sin(x) * cos(y)
f_ <- Deriv(f)
f_(3, 4)
#>         x         y 
#> 0.6471023 0.1068000

Created on 2020-02-02 by the reprex package (v0.3.0)

Sorry about that, I appreciate the link--although I should have probably done my own research on how to ask a question appropriately.

m <- function(x){x^3
}

b <- function(x,m){x^2+m^2
} 

Deriv(b)

# c(x = 2 * x, m = 2 * m)

My issue is that this does not take into account that m is a function of x, and so it seems like it is not using the chain rule. I am not sure how to make it so that what I am calling m in b is implicitly a function of x. I hope this clarifies.

Deriv does apply the chain rule, but we need a couple of tweaks to your code in order to get what you intended. In R, a function runs in its it own environment, so the m inside the function b is an argument that gets passed into b when you run b. It is not the function m that you defined outside of the function b.

First let's redefine our functions:

library(Deriv)

m <- function(x){
  x^3
}

b <- function(x, f){
  x^2 + f(x)^2
} 

Notice that b has two arguments. x is a number and f is a function. For example, b(3, m) will pass the function m into b, giving 738 (3^2 + m(3)^2 = 3^2 + 3^6=738). b(3, cos) will pass the cosine function into b, giving 9.98 (3^2 + cos(3)^2 = 9.98).

Now, to run Deriv, we need to pass b(x, m) into Deriv as an unevaluated expression, which we can do in at least two ways (see code below). We also add the x="x" argument to let Deriv know we want only the derivative with respect to "x":

Deriv(~b(x, m), x="x")
Deriv(quote(b(x, m)), x="x")

Either way, we get:

x * (2 + 6 * (x * m(x)))

which is 2x + 6x^2m(x)=2x+6x^5.

2 Likes

Hey! It's a learning process for everyone. Why do old doctors and lawyers still practice? Because that's exactly what it is!

I've found that a great way to figure out a problem is to get a really bonehead answer, like from an #OKBoomer whose last experience with differential equations was in the Johnson Administration, so I offer, without knowing what the result should be

suppressPackageStartupMessages(library(Deriv))
m <- function(x){x^3}
b <- function(x){x^2+m(x)^2} 
b_ <- Deriv(b)
b_(4)
#> [1] 6152

Created on 2020-02-02 by the reprex package (v0.3.0)

1 Like

Thank you very much for this!

May I ask what the difference is between ~ and quote? If it is too laborious to explain, no worries. I just want to clarify.

This might be a bit above my pay grade but I'll give it a shot. Hopefully others can jump in and expand on or, if necessary, correct my answer.

quote captures an R statement without evaluating it.
~ turns an R statement into a formula, which is also a way of delaying evaluation.

This would also work: Deriv(expression(b(x, m)), x="x"), because expression also delays evaluation. If you look at the help for Deriv (run ?Deriv in the console), it describes these and other ways to pass an expression to Deriv. It doesn't matter here which approach you use.

If we run Deriv(b(x,m), x="x"), R will try to immediately evaluate b(x,m). This will cause an error, because we didn't provide a value for the x argument. Delaying evaluation of b(x,m) allows Deriv to do whatever it's doing to symbolically evaluate the derivative.

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.