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
, and LabelledArrays.SLArray
)
Expressions that create sparse arrays
Do using SymbolicUtils.Code
to get the following bindings
toexpr
toexpr(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
.
These are all exported when you do using SymbolicUtils.Code
Assignment(lhs, rhs)
An assignment expression. Shorthand lhs ← rhs
(\leftarrow
)
Let(assignments, body[, let_block])
A Let block.
assignments
is a vector of Assignment
s
body
is the body of the let block
let_block
boolean (default=true) – do not create a let block if false.
Func(args, kwargs, body[, pre])
A function.
args
is a vector of expressions
kwargs
is a vector of Assignment
s
body
is the body of the function
pre
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 the Expr
form, it is given a random name, and is expected to receive a vector or tuple of size 2 containing the values of b
and y(t)
. The let block that is automatically generated "destructures" these arguments.
x(t)
and y(t)
have been replaced with var"x(t)"
and var"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 as x
and y
, but since the args
array contains f
as itself rather than as say, f(t)
, it does not become a var"f(t)"
. The generated function expects a function of one argument to be passed in the position of f
.
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"
SpawnFetch{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.
SetArray(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
.
MakeArray(elems, similarto, [output_eltype=nothing])
An expression which constructs an array.
elems
is the output array
similarto
can either be a type, or some symbol that is an array whose type needs to be emulated. If similarto
is a StaticArrays.SArray, then the output array is also created as an SArray
, similarly, an Array
will result in an Array
, and a LabelledArrays.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
@inlline 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.
MakeSpaseArray(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.
MakeTuple(tup)
Make a Tuple from a tuple of expressions.
LiteralExpr(ex)
Literally ex
, an Expr
. toexpr
on LiteralExpr
recursively calls toexpr
on any interpolated symbolic expressions.