Code generation
Note: this feature is experimental and the API might change frequently
toexpr(ex)
turns any expression (ex
) into the equivalent Expr
which is suitable for eval
. The SymbolicUtils.Code
module provides some combinators which provides the ability to construct more complex expressions than just function calls. These include:
- Let blocks
- Functions with arguments and keyword arguments
- Functions with arguments which are to be de-structured
- Expressions that set array elements in-place
- Expressions that create an array similar in type to a reference array (currently supports
Array
,StaticArrays.SArray
, andLabelledArrays.SLArray
) - Expressions that create sparse arrays
Do using SymbolicUtils.Code
to get the following bindings
toexpr
SymbolicUtils.Code.toexpr
— Functiontoexpr(ex, [st,])
Convert a symbolic expression into an Expr
, suitable to be passed into eval
.
For example,
julia> @syms a b
(a, b)
julia> toexpr(a+b)
:((+)(a, b))
julia> toexpr(a+b) |> dump
Expr
head: Symbol call
args: Array{Any}((3,))
1: + (function of type typeof(+))
2: Symbol a
3: Symbol b
Note that the function is an actual function object.
For more complex expressions, see other code-related combinators,
Namely Assignment
, Let
, Func
, SetArray
, MakeArray
, MakeSparseArray
and MakeTuple
.
To make your own type convertible to Expr using toexpr
define toexpr(x, st)
and forward the state st
in internal calls to toexpr
. st
is state used to know when to leave something like y(t)
as it is or when to make it var"y(t)"
. E.g. when y(t)
is itself the argument of a function rather than y
.
Code Combinators
These are all exported when you do using SymbolicUtils.Code
SymbolicUtils.Code.Assignment
— TypeAssignment(lhs, rhs)
An assignment expression. Shorthand lhs ← rhs
(\leftarrow
)
SymbolicUtils.Code.Let
— TypeLet(assignments, body[, let_block])
A Let block.
assignments
is a vector ofAssignment
sbody
is the body of the let blocklet_block
boolean (default=true) – do not create a let block if false.
SymbolicUtils.Code.Func
— TypeFunc(args, kwargs, body[, pre])
A function.
args
is a vector of expressionskwargs
is a vector ofAssignment
sbody
is the body of the functionpre
a vector of expressions to be prepended to the function body, for example, it could be[Expr(:meta, :inline), Expr(:meta, :propagate_inbounds)]
to create an@inline @propagate_inbounds
function definition.
Special features in args
:
- args can contain
DestructuredArgs
- call expressions
For example,
julia> @syms a b c t f(d) x(t) y(t) z(t)
(a, b, c, t, f(::Number)::Number, x(::Number)::Number, y(::Number)::Number, z(::Number)::Number)
julia> func = Func([a,x(t), DestructuredArgs([b, y(t)]), f], # args
[c ← 2, z(t) ← 42], # kwargs
f((a + b + c) / x(t) + y(t) + z(t)));
julia> toexpr(func)
:(function (a, var"x(t)", var"##arg#255", f; c = 2, var"z(t)" = 42)
let b = var"##arg#255"[1], var"y(t)" = var"##arg#255"[2]
f((+)(var"y(t)", var"z(t)", (*)((+)(a, b, c), (inv)(var"x(t)"))))
end
end)
- the second argument is a
DestructuredArgs
, in theExpr
form, it is given a random name, and is expected to receive a vector or tuple of size 2 containing the values ofb
andy(t)
. The let block that is automatically generated "destructures" these arguments. x(t)
andy(t)
have been replaced withvar"x(t)"
andvar"y(t)"
symbols throughout
the generated Expr. This makes sure that we are not actually calling the expressions x(t)
or y(t)
but instead passing the right values in place of the whole expression.
f
is also a function-like symbol, same asx
andy
, but since theargs
array containsf
as itself rather than as say,f(t)
, it does not become avar"f(t)"
. The generated function expects a function of one argument to be passed in the position off
.
An example invocation of this function is:
julia> executable = eval(toexpr(func))
#10 (generic function with 1 method)
julia> executable(1, 2.0, [2,3.0], x->string(x); var"z(t)" = sqrt(42))
"11.98074069840786"
SymbolicUtils.Code.SpawnFetch
— TypeSpawnFetch{ParallelType}(funcs [, args], reduce)
Run every expression in funcs
in its own task, the expression should be a Func
object and is passed to Threads.Task(f)
. If Func
takes arguments, then the arguments must be passed in as args
–a vector of vector of arguments to each function in funcs
. We don't use @spawn
in order to support RuntimeGeneratedFunctions which disallow closures, instead we interpolate these functions or closures as smaller RuntimeGeneratedFunctions.
reduce
function is used to combine the results of executing exprs
. A SpawnFetch expression returns the reduced result.
Use Symbolics.MultithreadedForm
ParallelType from the Symbolics.jl package to get the RuntimeGeneratedFunction version SpawnFetch.
ParallelType
can be used to define more parallelism types SymbolicUtils supports Multithreaded
type. Which spawns threaded tasks.
SymbolicUtils.Code.SetArray
— TypeSetArray(inbounds, arr, elems)
An expression representing setting of elements of arr
.
By default, every element of elems
is copied over to arr
,
but if elems
contains AtIndex(i, val)
objects, then arr[i] = val
is performed in its place.
inbounds
is a boolean flag, true
surrounds the resulting expression in an @inbounds
.
SymbolicUtils.Code.MakeArray
— TypeMakeArray(elems, similarto, [output_eltype=nothing])
An expression which constructs an array.
elems
is the output arraysimilarto
can either be a type, or some symbol that is an array whose type needs to be emulated. Ifsimilarto
is a StaticArrays.SArray, then the output array is also created as anSArray
, similarly, anArray
will result in anArray
, and aLabelledArrays.SLArray
will result in a labelled static array.output_eltype
: if set, then forces the element type of the output array to be this. by default, the output type is inferred automatically.
You can define:
@inline function create_array(A::Type{<:MyArray},a
::Nothing, d::Val{dims}, elems...) where dims
# and
@inline function create_array(::Type{<:MyArray}, T, ::Val{dims}, elems...) where dims
which creates an array of size dims
using the elements elems
and eltype T
, to allow MakeArray
to create arrays similarto MyArray
s.
SymbolicUtils.Code.MakeSparseArray
— TypeMakeSpaseArray(array)
An expression which creates a SparseMatrixCSC
or a SparseVector
.
The generated expression contains the sparsity information of array
,
it only creates the nzval
field at run time.
SymbolicUtils.Code.MakeTuple
— TypeMakeTuple(tup)
Make a Tuple from a tuple of expressions.
SymbolicUtils.Code.LiteralExpr
— TypeLiteralExpr(ex)
Literally ex
, an Expr
. toexpr
on LiteralExpr
recursively calls toexpr
on any interpolated symbolic expressions.