Symbolic Partial Derivatives of Expressions

DESCRIPTION:

deriv is a generic function which takes the partial derivative of a S-PLUS expression with respect to a given variable or variables.

USAGE:

deriv(expr, namevec, function.arg, tag=".expr", formal=F) 

REQUIRED ARGUMENTS:

expr
expression to be differentiated, typically a formula, in which case the expression returned computes the right side of the ~ and its derivatives.
namevec
character vector of names of parameters (derivatives are computed only for these variables only).

OPTIONAL ARGUMENTS:

function.arg
optional argument vector or prototype for a function. If present, the returned value is in the form of a function instead of a multiple statement expression. When function.arg is given as a function prototype, the function arguments can have defaults.
tag
base of the names to be given to intermediate results. Default ".expr".
formal
logical, if 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.

VALUE:

a multiple-statement expression or a function definition. When evaluated, these statements return the value of the original expression along with an attribute called "gradient". This is the gradient matrix of the expression value with respect to the named parameters.

DETAILS:

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.

EXAMPLES:

# 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.