deriv
is a generic function which takes the partial derivative of a
S-PLUS expression with respect to a given variable or variables.
deriv(expr, namevec, function.arg, tag=".expr", formal=F)
~
and its
derivatives.
function.arg
is given as a function
prototype, the function arguments can have defaults.
".expr"
.
TRUE
then
derivatives are with respect to formal parameters.
By default derivatives are with respect to actual function arguments,
and no gradient is produced if this is not possible.
See examples below.
Functions such as
nls
expect
formal=FALSE
.
"gradient"
. This is the
gradient matrix of the expression value with respect to the named
parameters.
deriv
is a generic function with a default method and a method for
formulas.
If
function.arg
is a character vector, the result is a function with
the arguments named in
function.arg
. If
function.arg
is a
function, the result is a function with the same arguments and default
values.
While generating this sequence of expressions, the function attempts
to eliminate repeated calculation of common subexpressions.
Sometimes user assistance is needed, as in the example below.
To
improve readability, expressions that are used only once are folded
back into the expression where they are used. Since parentheses are
always added when such expressions are folded in, there may be
redundant parentheses in the final expressions.
The symbolic differentiation and the simplification of the result are
highly recursive. Even for relatively simple expressions, S-PLUS can
reach its limit on the number of nested expressions and give an error
message.
The remedy is to increase the value of the option
expressions
when this happens.
# value and gradient of the Michaelis-Menten model deriv(~ Vm*conc/(K+conc),c("Vm","K")) expression({ .expr1 <- Vm * conc .expr2 <- K + conc .value <- .expr1/.expr2 .grad <- array(0, c(length(.value), 2), list(NULL, c("Vm", "K"))) .grad[, "Vm"] <- conc/.expr2 .grad[, "K"] <- - (.expr1/(.expr2^2)) attr(.value, "gradient") <- .grad .value } ) # to obtain a function as the result deriv(~ Vm*conc/(K+conc),c("Vm","K"), function(Vm, K, conc = 1:10) NULL) function(Vm, K, conc = 1:10) { .expr1 <- Vm * conc .expr2 <- K + conc .value <- .expr1/.expr2 .grad <- array(0, c(length(.value), 2), list(NULL, c("Vm", "K"))) .grad[, "Vm"] <- conc/.expr2 .grad[, "K"] <- - (.expr1/(.expr2^2)) attr(.value, "gradient") <- .grad .value } # Investigate the effect of the argument "formal": x <- 1:3; y <- 2:4 f <- deriv(~a^2, "a", function(a) NULL) f(x) # gradient with respect to "x" f(1:3) # no gradient -- nothing to differentiate f(x^2) # no gradient -- meaning is ambiguous f <- deriv(~a^2, "a", function(a) NULL, formal=T) f(1:3) # gradient "a" f(x) # gradient "a" f(x^2) # gradient "a" # In the case formal=T, a gradient is always attached, # with a single column with the name "a". This is the # value of the function f' = df/da, evaluated at the # actual input, ignoring all names of the input. # Investigate "formal" with two variables: g <- deriv(~a*b^2, c("a","b"), function(a,b) NULL) g(x, y) # gradient has columns "x", "y" g(1:3, 2:4) # no gradient - nothing to differentiate g(x, x) # columns x, x -- this is DANGEROUS. # You should use unique variable names when using formal=F g <- deriv(~a*b^2, c("a","b"), function(a,b) NULL, formal=T) g(x, y) # gradient has columns "a", "b" g(1:3, 2:4) # gradient has columns "a", "b" g(x, x) # gradient has columns "a", "b" # With formal=T, the columns of the gradient are the values # of the functions df/da and df/db, evaluated at the # actual input.