# Simplify an Expr

**URL:** https://discourse.julialang.org/t/simplify-an-expr/73960
**Category:** New to Julia
**Tags:** symbolics
**Created:** [January 3, 2022, 11:56am UTC](https://discourse.julialang.org/t/simplify-an-expr/73960 "2022-01-03T11:56:12Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![Bardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bardo/32/21601_2.png) [@Bardo](https://discourse.julialang.org/u/Bardo)
#### Post date: [January 3, 2022, 11:56am UTC](https://discourse.julialang.org/t/simplify-an-expr/73960/1 "2022-01-03T11:56:12Z")

</div>

In the context of code generation, I want to write a code simplification routine.  
Input and output are of type Expr.  
A[i] and b[i] can take as sparsity pattern `:null, :plusone, :minusone, :other`

Example:  
`expr = :(A[1] = A[1] + A[2] * b[3])`  
Depending on actual values, `expr` can be simplified to

```julia
:(A[1] = A[1] + A[2] * b[3]) # if all have value :other
:(A[1] = A[1] + b[3]) # if A[2] == :plusone
...
nothing::Nothing # if A[2] * b[3] == 0

```

[kmsquire/Match.jl: Advanced Pattern Matching for Julia (github.com)](https://github.com/kmsquire/Match.jl) looks promising for simple, fixed-form expressions which can be solved by hand.  
[MasonProtter/Rewrite.jl: Term rewriting in Julia (github.com)](https://github.com/MasonProtter/Rewrite.jl) appears more general, but works with symbolic expressions. So maybe as intermediate form.  
Other ideas?

---

<div class="post-metadata">

### Author: ![tikej](https://avatars.discourse-cdn.com/v4/letter/t/b5a626/32.png) [@tikej](https://discourse.julialang.org/u/tikej)
#### Post date: [January 3, 2022, 2:00pm UTC](https://discourse.julialang.org/t/simplify-an-expr/73960/2 "2022-01-03T14:00:53Z")

</div>

I think what you need could be done with [Metatheory.jl](https://juliasymbolics.github.io/Metatheory.jl/dev/) and it’s probably what you’re looking for. Otherwise, if you prefer to do it similarly to Rewrite.jl there is [SymbolicUtils](https://github.com/JuliaSymbolics/SymbolicUtils.jl) package, that works with symbolic expressions. Finally in [Symbolics.jl there is support for symbolic arrays](https://symbolics.juliasymbolics.org/dev/manual/arrays/#Symbolic-arrays-1), not sure whether it includes sparsity patterns ATM, but you could check.

So depending on how “low-level” you want to go with simplifications, it’s probably one of these three packages.

---

<div class="post-metadata">

### Author: ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)
#### Post date: [January 3, 2022, 7:18pm UTC](https://discourse.julialang.org/t/simplify-an-expr/73960/3 "2022-01-03T19:18:27Z")

</div>

[Espresso.jl](https://github.com/dfdx/Espresso.jl/) might also be useful for you, especially [rewrite.jl](https://github.com/dfdx/Espresso.jl/blob/master/src/rewrite.jl).

---

<div class="post-metadata">

### Author: ![Bardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bardo/32/21601_2.png) [@Bardo](https://discourse.julialang.org/u/Bardo)
#### Post date: [January 4, 2022, 5:05pm UTC](https://discourse.julialang.org/t/simplify-an-expr/73960/4 "2022-01-04T17:05:11Z")

</div>

Thanks for all your suggestions!  
Before calling in the cavalry, I looked a bit closer and finished with some rules working directly on the expression.

```julia

"""
Simplification of elementary expressions in sparse linear solver loops
"""
simple(e) = error("not expected type: $(typeof(e))")
simple(e::Number) = e
function simple(e::Symbol)
    ev = eval(e)
    if ev == 0 return 0
    elseif ev == 1 return 1
    elseif ev == -1 return -1
    else return e
    end
end
function simple(e::Expr)
    if e.head == :(=)
        if eval(e.args[1]) ≈ eval(e.args[2]) # (redundant operation)
            return nothing::Nothing
        else
            e.args[2] = simple(e.args[2])
        end
    elseif e.head == :call 
        e.args[2] = simple(e.args[2])
        e.args[3] = simple(e.args[3])
        ev2 = eval(e.args[2])
        ev3 = eval(e.args[3])
        if e.args[1] == :*
            if ev2 == 1 # 1 * a -> a
                e = e.args[3]
            elseif ev3 == 1 # a * 1 -> a
                e = e.args[2] 
            elseif ev2 == -1 # -1 * a -> -a
                e = Expr(:call, :-, e.args[3])
            elseif ev3 == -1 # a * -1 -> -a
                e = Expr(:call, :-, e.args[2]) 
            end
        elseif e.args[1] == :/
            if ev3 == 1 # a / 1 -> a
                e = e.args[2]
            elseif ev3 == -1 # a / -1 -> -a
                e = Expr(:call, :-, e.args[2]) 
            end
        elseif e.args[1] == :+
            if ev2 == 0 # 0 + a -> a
                e = e.args[3]
            elseif ev3 == 0 # a + 0 -> a
                e = e.args[2]
            end
        end
    end
    return e
end

# Tests
a = π
b = sqrt(2)
a0 = 0
ap1 = 1
am1 = -1
simple(:(a = a + (a * a0 * b)/a)) # nothing::Nothing
simple(:(a = ap1 * am1)) # :(a = -1)
simple(:(a = ap1 * b)) # :(a = b)
simple(:(a = a + am1 * b)) # :(a = a + -b)
simple(:(a = a + am1 / b)) # :(a = a + -1 / b)
simple(:(a = 2*a + a / b)) # (unchanged)

```
