On Apr 28, 2016 7:15 AM, "Ben Lauwens" <[email protected]> wrote:
>
> Hi
>
> I like to create automatically functions that evaluates the total
derivative of a function with respect to time, eg.
> given f(t, x1, x2) = t^2+x1*x2, I want to obtain
df/dt(t,x1,x2,dx1/dt,dx2/dt) = 2t+x1*dx2/dt+x2*dx1/dt,
d2f/dt2(t,x1,x2,dx1/dt,dx2/dt,d2x1/dt2,d2x2/dt) =
2+2dx1/dt*dx2/dt+x1*d2x2/dt2+x2*d2x1/dt2, and so on.
> The initial function is specified as a string as are the arguments.
> The following code using the Calculus package works nicely:
> using Calculus
>
> function total_derivatives_with_respect_to_time(f::AbstractString,
order::Int, names::AbstractString...)
>   derivs = Array(Function, order)
>   n = length(names)
>   args = AbstractString["t", names...]
>   derivs[1] = eval(parse("($(reduce((a,b)->"$a,$b",args)))->$f"))
>   if order > 1
>     fun = f
>     for o = 2:order
>       ∇fun = differentiate(fun, args)
>       dfun = AbstractString["$(∇fun[1])"]
>       for i = 1:n
>         push!(args, "d$(o-1)_$(names[i])")
>       end
>       for j = 2:(o-1)*n+1
>         push!(dfun, "($(∇fun[j])) * $(args[j+n])")
>       end
>       fun = reduce((a,b)->"$a + $b", dfun)
>       derivs[o] = eval(parse("($(reduce((a,b)->"$a,$b",args)))->$fun"))
>     end
>   end
>   return derivs
> end
>
> derivs = total_derivatives_with_respect_to_time("t^2+x1*x2", 3, "x1",
"x2")
> println(derivs[1](1.0, 2.0, 3.0))
> println(derivs[2](1.0, 2.0, 3.0, 4.0, 5.0))
> println(derivs[3](1.0, 2.0, 3.0, 4.0, 5.0, -1.0, -2.0))

For calculating derivatives there may be better ways (forwarddiff and other
packages). In general, generating functions with eval is fine as long as
you dont do that in the performance critical part. However, you should
never use parse and should construct the AST directly.

> I have however the feeling that I am abusing the sequence of eval and
parse to automatically generate anonymous function. Is there a way to do
this more elegantly? Performance wise the code runs fine in Julia v0.5.
>
> Ben

Reply via email to