On Thu, Apr 28, 2016 at 6:05 PM, Josh Langsfeld <[email protected]> wrote:
> That's quite a strong statement to say never use parse. Could you explain? I
> think manipulating strings is typically much easier than Expr objects.

I don't believe that is true. String processing is slow, error prone
and unsafe. Constructing a AST using splicing is more straightforward
and more understandable than string splicing. Matching/processing  an
AST is also much easier than pattern matching and replacing in string.
There's good reason AST processing are not done on strings directly.

As an example, just compare the use of parse in the code provided.
Note that strings are assumed to be replaced with symbols and
expressions since that's what should be used for AST processing.

parse("($(reduce((a,b)->"$a,$b",args)))->$f")
vs
:(($(args...))->$f)

fun = reduce((a,b)->"$a + $b", dfun)
parse("($(reduce((a,b)->"$a,$b",args)))->$fun")
vs
:(($(args...))->+($(dfun...)))

>
> On Thursday, April 28, 2016 at 8:38:27 AM UTC-4, Yichao Yu wrote:
>>
>>
>> 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