Taylor expansion in Symbolics

I found the very useful library

https://github.com/JuliaDiff/TaylorSeries.jl

and was able to use it to generate the Taylor series coefficients for a problem I was working on.

I thought to myself this would be a really cool thing to implement in Symbolics, just for fun, and immediately got into trouble :wink:

the goal: create a function to generate a Taylor series by generating the derivatives of a function and returning the coefficients of that Taylor series, and for bonus points return a function which can be evaluated in code.

As i pointed out this can all be done with the TaylorSeries package, this is a learning experience for me, and I thought it might be useful to others.

I did the obvious thing, trying to generate the 1st derivative:

using Symbolics

function main()
    @variables x
    f(x) = log(1+x)
    df = Symbolics.derivative(f(x),x)
    println(df)
    # @syms df(x)
    println(df(2))
    println(df(3))
end

main()

and saw:

(1 + x)^-1
ERROR: LoadError: Sym (1 + x)^-1 is not callable. Use @syms (1 + x)^-1(var1, var2,...) to create it as a callable.
ste code here

I then tried a bunch of stuff based what i was reading in the documentation to try and get df(2) and df(3) to yield a numeric value but the best i could ever do was get “df(2)” and “df(3)” to print.

hoping i could get some advice and how to move this further along.

thank you!

Instead of df(2) do substitute(df,2)

No success.

println(SymbolicUtils.substitute(df,2))

`ERROR: LoadError: MethodError: no method matching haskey(::Int64, ::Num)
Closest candidates are:
haskey(::DataStructures.SwissDict, ::Any) at /home/briand/.julia/packages/DataStructures/ixwFs/src/swiss_dict.jl:534

looking at the documentation, it seems to me like substitute is meant to substitute a different expression, not to evaluate an expression numerically.

FYI, i have tried using build_function in various ways without success, thinking that I might be able to get that to return something that could be used to evaluate at a value.

edit:
The answer is…
println(SymbolicUtils.substitute(df,Dict(x=>2.0)))

My goal is to of course generate a function which is compiled in as code, but give me some time to get through the documentation :slight_smile:

Please post the answer to the above, others might be interested too!

Some time ago, I was playing a little bit with this; you may have a look in the lb/Symbolics branch. The following is produced using that branch:

julia> using Symbolics, TaylorSeries

julia> x = t₀ + Taylor1(5)
 t₀ + 1.0 t + 𝒪(t⁶)

julia> sin(x)
 sin(t₀) + cos(t₀) t + -0.5sin(t₀) t² + -0.16666666666666666cos(t₀) t³ + 0.041666666666666664sin(t₀) t⁴ + 0.008333333333333333cos(t₀) t⁵ + 𝒪(t⁶)

julia> 1/x
 1 / t₀ + (-(1 / t₀)) / t₀ t + (-((-(1 / t₀)) / t₀)) / t₀ t² + (-((-((-(1 / t₀)) / t₀)) / t₀)) / t₀ t³ + (-((-((-((-(1 / t₀)) / t₀)) / t₀)) / t₀)) / t₀ t⁴ + (-((-((-((-((-(1 / t₀)) / t₀)) / t₀)) / t₀)) / t₀)) / t₀ t⁵ + 𝒪(t⁶)

I would love to. Gave up. Couldn’t figure it out.

Should probably give it another try, because i’d generally like to be able to do that for functions other than just Taylor series expansions.

Did you look at Luis’ branch?

1 Like

I have not, but thanks for pointing it out. i’ll be sure an take a look.

Is this useful to you?

using Symbolics, TaylorSeries

@variables x e
f = sin(x)

dx = Differential(x)
order = 5
taylor_seriesₓ₊ₑ = f + sum((dx^i)(f)*e^i/factorial(BigInt(i)) for i in 1:order) |> expand_derivatives
substitute(taylor_seriesₓ₊ₑ, Dict(x=>0.0))     # coefficients

# alternative
# @variables x₀
# series = substitute(f, Dict(x=>x₀)) + sum(substitute((dx^i)(f)|>expand_derivatives, Dict(x=>x₀))*(x-x₀)^i/factorial(i) for i in 1:order)
# substitute(series, Dict(x₀=>0.0))
#

t = Taylor1(5)
sin(t)     # same coefficients with TaylorSeries.jl

f_taylor_5_order = Symbolics.build_function(taylor_seriesₓ₊ₑ, x, e) |> eval  # callable julia function
f_taylor_5_order(0.0, 0.1)  # example
1 Like