JuliaSymbolics / Symbolics.jl

Symbolic programming for the next generation of numerical software

Home Page:https://symbolics.juliasymbolics.org/stable/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wrong answer for derivative at branch points

LilithHafner opened this issue · comments

The function f(x) == ifelse(x == 0, 0, x) over the reals is mathematically equal to function f(x) = x. It is continuously differentiable wit ha derivative of 1 everywhere. However, Symbolics.jl miscomputes it's value at zero:

julia> Symbolics.derivative(ifelse(x == 0, 0, x), x)
ifelse(x == 0, 0, 1)

Better answers would be 1, ifelse(x == 0, 1, 1), or ifelse(x == 0, UNKNOWN, 1).

Getting the right answer on this sort of edge case is hard. It requires full symbolic limit calculation. A reduction from symbolic limit calculation to symbolic differentiation follows:

Take an arbitrary expression expr and variable x. To compute the limit of expr as x approaches 0, consider the expression expr2 = ifelse(x == 0, 0, x*expr). The derivative of expr2 with respect to x, evaluated at x0 is defined as the limit as h -> 0 of (expr2(x0+h) - expr2(x0)) / h. Setting x0 to zero we find the derivative of expr2 with respect to x, evaluated at 0 is the limit as h -> 0 of (expr2(0+h) - expr2(0)) / h = (expr2(h) - 0) / h = expr2(h) / h. Because we are taking the limit as h -> 0, we can assume h != 0 and simplify to expr2(h) / h = h*expr(h) / h = expr(h). Thus the derivative of expr2 with respect to x evaluated at zero is equal to the limit of expr as x approaches zero. Because expr and x were arbitrary, any two-sided limit at zero can be trivially solved with a symbolic derivative oracle.