Add a new node to a graph. Expression should be simple, e.g. nested calls or blocks are not allowed (use parse!() for it).


Collect all replacable variables from a chain of assignments in a graph. Variables y and x are considered replacable if there's a node y = x and both variables have the same set of guards. Note that this allows nodes to have different sets of indices.


Return canonical representation of a function name, e.g.:

Base.+  ==> +
Main.+  ==> + (resolved to Base.+)
Base.LinAlg.exp ==> exp ==>

For each variable in graph, calculate all variables that depend on it. This is essentially the opposite of dependencies(nd::ExNode), but operates on variable names rather than nodes.


Replace all struct arguments by a list of their plain analogues. Example:

args = [:m, :x, :y]
types = (Linear, Matrix{Float64}, Matrix{Float64})
ex = :(sum((m.W * x .+ m.b) - y))

destruct(args, types, ex)
# ==>
# ([:m_W, :m_b, :x, :y],
#  :(sum((m_W * x .+ m_b) - y)),
#  Dict(:(m.W) => :m_W, :(m.b) => :m_b))

Given a list of symbols such as [:x, :y, :z] constructs expression x.y.z. This is useful for building expressions of qualified names such as Base.LinAlg.exp.


For buffered codegens, return unbuffered version that can be used in evaluate!()


Evaluate node, i.e. fill its val by evaluating node's expression using values of its dependencies.


find_vars(ex; rec=true)

Same as get_vars(), but recursive by default


Find sub-expressions matching a pattern. Example:

ex = :(a * f(x) + b * f(y))
pat = :(f(_))
findex(pat, ex)   # ==> [:(f(x)), :(f(y))]

Given a list of expression arguments, flatten the dotted ones. Example:

args = [:foo, :([a, b, c]...)]
# ==> [:foo, :a, :b, :c]

Collapse unnecessary assignment nodes, rewriting all affected nodes. Example:

tmp1 = x * y
z = tmp1

will be rewritten to

z = x * y

Generate a new unique name for intermediate variable in graph


Looks up the source of method in the file path found in method. Returns the AST and source string, might throw an LoadError if file not found.


Get variables (Symbol or Expr(:ref)) involved in exprssion


A single number to represent a graph. Insensitive to variable names.


Given a symbolic name, either adds 2 to the end or increment existing number. Example:

inc_var_name(:x)   # ==> x2
inc_var_name(:x2)  # ==> x3

Check if all operations in this expression are broadcasting


Check if an object is of a struct type, i.e. not a number or array


Make call expression from function name, ordinary and keyword arguments.

The reverse of this operation is parsecallexpr()


Make indexed variable. Examples:

make_indexed(:x, [])       ==> :x
make_indexed(:x, [:i,:j])  ==> :(x[i,j])

See also: split_indexed


Find definition of a called function and build its subgraph ready for inlining


Match expression ex to a pattern pat, return nullable dictionary of matched symbols or rpatpressions. Example:

ex = :(u ^ v)
pat = :(_x ^ _n)
matchex(pat, ex)
# ==> Union{ Dict{Symbol,Any}(:_n=>:v,:_x=>:u), Void }

NOTE: two symbols match if they are equal or symbol in pattern is a placeholder. Placeholder is any symbol that starts with ''. It's also possible to pass list of placeholder names (not necessarily starting wiht '') via phs parameter:

ex = :(u ^ v)
pat = :(x ^ n)
matchex(pat, ex; phs=Set([:x, :n]))
# ==> Union{ Dict{Symbol,Any}(:n=>:v,:x=>:u), Void } 

Several elements may be matched using ... expression, e.g.:

ex = :(A[i, j, k])
pat = :(x[I...])
matchex(pat, ex; phs=Set([:x, :I]))
# ==> Union{ Dict(:x=>:A, :I=>[:i,:j,:k]), Void }

Optional parameters:

  • phs::Set{Symbol} = DEFAULT_PHS[1] A set of placeholder symbols

  • allow_ex::Boolean = true Allow matchinng of symbol pattern to an expression. Example:

        matchex(:(_x + 1), :(a*b + 1); allow_ex=true)  # ==> matches
        matchex(:(_x + 1), :(a*b + 1); allow_ex=false)  # ==> doesn't match
  • exact::Boolean = false Allow matching of the same expression to different keys

        matchex(:(_x + _y), :(a + a); exact=false) # ==> matches
        matchex(:(_x = _y), :(a + a); exact=true)  # ==> doesn't match

Parse Julia expression and build ExGraph in-place. Return the the output variable.


Parse call expression into function name, ordinary and keyword arguments. :kw and :parameters arguments are treated the same way.

The reverse of this operation is makecallexpr()


Propagate substitution rules. Example:

    :x => y,
    :y => z

is transformed into:

    :x => z,
    :y => z

Try to recover an expression from a lowered form. Example:

ex = (Main.sum)((Base.literal_pow)(Main.^, (Base.broadcast)(Main.-, (Main.predict)(W, b, x), y), (Core.apply_type)(Base.Val, 2)))

Removes unused variables from multiline expressions, e.g. in:

x = u * v
y = x + 1
z = 2x

y isn't used to compute output variable z, so it's removed:

x = u * v
z = 2x

rewrite(ex, pat, rpat)

Rewrite expression ex according to a transform from pattern pat to a substituting expression rpat. Example (derivative of x^n):

ex = :(u ^ v)
pat = :(_x ^ _n)
rpat = :(_n * _x ^ (_n - 1))
rewrite(ex, pat, rpat) # ==> :(v * u ^ (v - 1))

rewrite_all(ex, rules)

Recursively rewrite an expression according to a list of rules like [pat => rpat] Example:

ex = :(foo(bar(foo(A))))
rules = [:(foo(x)) => :(quux(x)),
         :(bar(x)) => :(baz(x))]
rewrite_all(ex, rules; phs=[:x])
# ==> :(quux(baz(quux(A))))

rewrite_all(ex, pat, rpat)

Recursively rewrite all occurrences of a pattern in an expression. Example:

ex = :(foo(bar(foo(A))))
pat = :(foo(x))
rpat = :(quux(x))
rewrite_all(ex, pat, rpat; phs=[:x])
# ==> :(quux(bar(quux(A))))

Simplify expression x by applying a set of rules. Common examples of simplification include calculation of fully numeric subexpressions, removing needless multiplication by 1, etc.

Use macro @simple_rule to add new simplification rules.


Split possibly indexed variable into a name and indices. Examples:

split_indexed(:x)         ==> (:x, [])
split_indexed(:(x[i,j]))  ==> (:x, [:i,:j])

See also: make_indexed


Split parameters of a function signature, returning a list of (param name, param type) tuples and a list of keyword parameters.

See also: parsecallargs


Substitute symbols in ex according to substitute table st. Example:

ex = :(x ^ n)
subs(ex, x=2)            # ==> :(2 ^ n)


subs(ex, Dict(:x => 2))  # ==> :(2 ^ n)

If ex contains a :(xs...) argument and st contains an array-valued sabstitute for it, the substitute will be flattened:

ex = :(foo(xs...))
subs(ex, Dict(:xs => [:a, :b, :c]))
# ==> :(foo(a, b, c))

Convert ExNode to a full expression, e.g. for vectorized notation:

z = x + y

or for indexed notation:

z[i] = x[i] + y[i]

Same as rewrite, but returns Union{Expr, Void} and doesn't throw an error when expression doesn't match pattern


Remove rpatpression conforming to a pattern. Example:

ex = :(x * (m == n))
pat = :(_i == _j)
ex = without(ex, pat)  # ==> :x

Same as get function, but evaluates default_expr only if needed


Get array of size sz from a dict by key. If element doesn't exist or its size is not equal to sz, create and return new array using default_expr. If element exists, but is not an error, throw ArgumentError.


Same as @get, but immediately exits function and return default_expr if key doesn't exist.


Macro to add simplification rules. Example:

@simple_rule (-x * -y) (x * y)

where (-x * -y) is a pattern to match expression and (x * y) is what it should be transformed to (see rewrite() to understand expression rewriting). Symbols Set([:a, :b, :y, :x]) may be used as placeholders when defining new rules, all other symbols will be taken literally.


Define a function or broadcasting rule for the specified signature which computes the result as for ordinary (not tracked) data and writes it to the graph.

Note: this function expects at least 1 parameter of TrackedReal or TrackedArray type with name x.