Automatic Conversion of Julia Code to C Functions
Since Symbolics.jl can trace Julia code into Symbolics IR that can be built and compiled via build_function to C, this gives us a nifty way to automatically generate C functions from Julia code! To see this in action, let's start with the Lotka-Volterra equations:
using Symbolics
function lotka_volterra!(du, u, p, t)
x, y = u
α, β, δ, γ = p
du[1] = dx = α*x - β*x*y
du[2] = dy = -δ*y + γ*x*y
endlotka_volterra! (generic function with 1 method)Now we trace this into Symbolics:
@variables t du[1:2] u[1:2] p[1:4]
du = collect(du)
lotka_volterra!(du, u, p, t)
du\[ \begin{equation} \left[ \begin{array}{c} p_{1} ~ u_{1} - p_{2} ~ u_{1} ~ u_{2} \\ - p_{3} ~ u_{2} + p_{4} ~ u_{1} ~ u_{2} \\ \end{array} \right] \end{equation} \]
and then we build the C source (the default is expression=Val{true}):
ccode = build_function(du, u, p, t, target=Symbolics.CTarget(), expression=Val{true})"#include <math.h>\nvoid diffeqf(double* du, const double* RHS1, const double* RHS2, const double RHS3) {\n du[0] = RHS2[0] * RHS1[0] + -1 * RHS2[1] * RHS1[0] * RHS1[1];\n du[1] = -1 * RHS2[2] * RHS1[1] + RHS2[3] * RHS1[0] * RHS1[1];\n}\n"CTarget returns C source as a String. It does not invoke a C compiler or return a Julia callable: expression=Val{false} throws an error. Compile the generated source yourself, load it with Libdl, and call it via ccall.
The following compile-and-call steps require a C compiler such as gcc. They are shown as non-executing documentation so the docs build does not depend on a compiler being present in the documentation environment.
using Libdl
# Write the generated C to a temporary shared library
libdir = mktempdir()
libpath = joinpath(libdir, "lotka." * dlext)
open(`gcc -fPIC -O3 -xc -shared -o $libpath -`, "w") do io
print(io, ccode)
end
# Call the C function (default fname is :diffeqf)
du = rand(2); du2 = rand(2)
u = rand(2)
p = rand(4)
t = rand()
ccall((:diffeqf, libpath), Cvoid,
(Ptr{Float64}, Ptr{Float64}, Ptr{Float64}, Float64),
du, u, p, t)
lotka_volterra!(du2, u, p, t)
du == du2 # true!