Function Definition Macros

DifferentialEquations.jl provides a set of macros for more easily and legibly defining your differential equations. It exploits the standard notation for mathematically writing differential equations and the notation for "punching differential equations into the computer"; effectively doing the translation step for you. This is best shown by an example. Say we want to solve the ROBER model. Using the @ode_def macro from ParameterizedFunctions.jl, we can do this by writing:

using ParameterizedFunctions
f = @ode_def ROBERExample begin
  dy₁ = -k₁*y₁+k₃*y₂*y₃
  dy₂ =  k₁*y₁-k₂*y₂^2-k₃*y₂*y₃
  dy₃ =  k₂*y₂^2
end k₁ k₂ k₃

This looks just like pseudocode! The macro will expand this to the "standard form", i.e. the ugly computer form:

function f(du,u,p,t)
  du[1] = -p[1]*u[1] + p[3]*u[2]*u[3]
  du[2] = p[1]*u[1] - p[2]*u[2]^2 - p[3]*u[2]*u[3]
  du[3] = p[2]*u[2]^2

Note that one doesn't need to use numbered variables: DifferentialEquations.jl will number the variables for you. For example, the following defines the function for the Lotka-Volterra model:

f = @ode_def LotkaVolterraExample begin
  dx = a*x - b*x*y
  dy = -c*y + d*x*y
end a b c d


The macro is a Domain-Specific Language (DSL) and thus has different internal semantics than standard Julia functions. In particular:

  1. Control sequences and conditionals (while, for, if) will not work in the macro.

  2. Intermediate calculations (likes that don't start with d_) are incompatible with the Jacobian etc. calculations.

  3. The macro has to use t for the independent variable.

Extra Optimizations

Because the ParameterizedFunction defined by the macro holds the definition at a symbolic level, optimizations are provided by SymEngine. Using the symbolic calculator, in-place functions for many things such as Jacobians, Hessians, etc. are symbolically pre-computed. In addition, functions for the inverse Jacobian, Hessian, etc. are also pre-computed. In addition, parameter gradients and Jacobians are also used.

Normally these will be computed fast enough that the user doesn't have to worry. However, in some cases you may want to restrict the number of functions (or get rid of a warning). Macros like @ode_def_nojac turn off the Jacobian calculations, and @ode_def_noinvjac turns off the Jacobian inversion. For more information, please see the ParameterizedFunctions.jl documentation.