Here is another challenge:
Thanks for your help. You actually somewhat predicted my next goal, but I wanted something different:
hdf(expr,p::Int) = horner(df(expr,:x,p))
function genfun(fun::Symbol,expr;depth=-1)
if depth < 0
@eval begin
@generated function $fun(x,::Val{p}) where p
expr = $(Expr(:quote,expr))
:(@fastmath $(horner(df(expr,:x,p))))
end
$fun(x,p::Int) = $fun(x,Val(p))
end
else
lexpr = [Expr(:quote,hdf(expr,i)) for i ∈ 0:depth-1]
@eval begin
N = 1+$depth
expr = $lexpr
function $fun(x,p)
macroexpand(quote
Base.Cartesian.@nif($N,
i->(i-1 == p),
i->($(:(expr[i]))),
i->throw(error("$(p)-th derivative not supported")))
end)
end
end
end
end
So the purpose of this function is that you can either make a generated function that evaluates derivatives up to arbitrary depth by default (with slower performance), but one should have the option of specifying a depth limit, which should then produce a plain function that uses the if-then-else structure.
julia> genfun(:fa,:(x^2))
fa (generic function with 2 methods)
julia> fa(2,0)
4
So the generated function now works properly. However, producing the right kind of if-then-else plain function for faster performance requires the expr[i]
derivatives to be inserted in each conditional.
In order to help debug this, the produced function outputs the if-then-else code instead of evaluating:
julia> genfun(:fb,:(x^2);depth=2)
fb (generic function with 1 method)
julia> fb(2,0)
quote # REPL[211], line 17:
if 0 == p
expr[1]
else
if 1 == p
expr[2]
else
throw(error("$(p)-th derivative not supported"))
end
end
end
If someone could figure out how to insert / interpolate expr[i]
into that, I would be very thankful.
Otherwise, instead of using Base.Cartesian.@nif
, a new function needs to take care of it.