Espresso ducumentation and thanks for all the fish

Espresso.jl Documentation

Expression parsing and rewriting

Expression matching

matchex - match expression by pattern, extract matching elements. Elements of expression are matched to placeholders - symbols in pattern that start with '_' or any symbols passed in phs parameter.

matchex(:(_x^2), :(u^2))
# Nullable(Dict{Symbol,Any}(:_x=>:u))
matchex(:(x^n), :(u^2); phs=Set([:x, :n]))
# Nullable(Dict{Symbol,Any}(:x=>:u,:n=>2))

See also matchingex. See also findex.

Expression substitution

subs - substitute elements of in expression according to substitution table:

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

Expression rewriting

rewrite - rewrite an expression matching it to a pattern and replacing corresponding placeholders in substitution expression.

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

See also tryrewrite.

Expression simplification

simplify - simplify numeric expression if possible.

simplify(:(2 - 1))
# 1
simplify(:(1 * (2x^1)))
# :(2x)

Einstein indexing notation

Espresso.jl also supports expressions in Einstein indexing notation and is mostly compatible with Einsum.jl. The most important functions are:

to_einstein - convert vectorized expression to Einstein notation.

to_einstein(:(W*x + b); W=rand(3,4), x=rand(4), b=rand(3))
# quote
#    tmp1[i] = W[i,k] * x[k]
#    tmp2[i] = tmp1[i] + b[i]
# end

Here W=rand(3,4), x=rand(4) and b=rand(3) are example values - anything that has the same type and dimensions as real expected values.

from_einstein - convert an expression in Einstein notation to vectorized form if possible.

from_einstein(:(W[i,k] * x[k] + b[i]))
# quote
#     tmp1 = W * x
#     tmp2 = tmp1 + b
# end

ExGraph

On low-level many functions of Espresso.jl use ExGraph - expression graph, represented as a topologically sorted list of primitive expression. Example:

g = ExGraph(:(W*x + b); W=rand(3,4), x=rand(4), b=rand(3))
# ExGraph
#   ExNode{input}(W = W | <Array{Float64,2}>)
#   ExNode{input}(x = x | <Array{Float64,1}>)
#   ExNode{input}(b = b | <Array{Float64,1}>)
#   ExNode{call}(tmp1 = W * x | nothing)
#   ExNode{call}(tmp2 = tmp1 + b | nothing)

The main advantage of using such representation is that each node represents exactly one simple enough expression such as assignment or function call. For example, to_einstein and from_einstein both use ExGraph to find rule for transforming between two notations.

Functions

# Espresso.matchexMethod.

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)
# ==> Nullable(Dict{Symbol,Any}(:_n=>:v,:_x=>:u))

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]))
# ==> Nullable(Dict{Symbol,Any}(:n=>:v,:x=>:u))

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

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

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

source

Index