@@ -195,11 +195,22 @@ julia> R(sin(sin(sin(x -1))), depth=2)
195195cos (cos (sin ((x + - 1 ))))
196196```
197197
198- ## Type conversion interface
198+ ## Interfacing with SymbolicUtils.jl
199199
200200This section is for Julia package developers who may want to use the ` simplify ` and rule rewriting system on their own expression types.
201201
202- The following functions should be defined for ` T ` to work.
202+ Our intention is for SymbolicUtils to be useful even for packages with their own custom symbolic types which
203+ differ from those offered by SymbolicUtils. To this end, SymbolicUtils provides an interface to convert expression
204+ tree types which have
205+ * an ` operation ` , (i.e. function to apply)
206+ * ` arguments ` which the ` operation ` is applied to
207+ * ` variable ` types which are the atoms from which the expression tree is built
208+ * optionally, a type which should ` typeof(operation(arguments...)) ` should return if it were to be run.
209+
210+ SymbolicUtils uses a function ` to_symbolic ` to convert aribtrarty types to it's own internal types.
211+
212+ The following methods should be defined for an expression tree type ` T ` with symbol types ` S ` to work
213+ with SymbolicUtils.jl
203214
204215#### ` istree(x::T) `
205216
@@ -221,6 +232,17 @@ Returns the arguments (a `Vector`) for an expression tree.
221232Called only if ` istree(x) ` is ` true ` . Part of the API required
222233for ` simplify ` to work. Other required methods are ` operation ` and ` istree `
223234
235+ #### ` to_symbolic(x::S) `
236+ Convert your variable type to a ` SymbolicUtils.Variable ` . Suppose you have
237+ ``` julia
238+ struct MySymbol
239+ s:: Symbol
240+ end
241+ ```
242+ which could represent any type symbolically, then you would define
243+ ``` julia
244+ SymbolicUtils. to_symbolic (s:: MySymbol ) = SymbolicUtils. Variable (s. s)
245+ ```
224246
225247### Optional
226248
@@ -239,3 +261,73 @@ rules that may be implemented in the future.
239261#### ` promote_symtype(f, arg_symtypes...) `
240262
241263Returns the appropriate output type of applying ` f ` on arguments of type ` arg_symtypes ` .
264+
265+ ### Example
266+
267+ Suppose you were feeling the temptations of type piracy and wanted to make a quick and dirty
268+ symbolic library built on top of Julia's ` Expr ` type, e.g.
269+
270+ ``` julia
271+ for f ∈ [:+ , :- , :* , :/ , :^ ] # Note, this is type piracy!
272+ @eval begin
273+ Base.$ f (x:: Union{Expr, Symbol} , y:: Number ) = Expr (:call , $ f, x, y)
274+ Base.$ f (x:: Number , y:: Union{Expr, Symbol} ) = Expr (:call , $ f, x, y)
275+ Base.$ f (x:: Union{Expr, Symbol} , y:: Union{Expr, Symbol} ) = (Expr (:call , $ f, x, y))
276+ end
277+ end
278+
279+
280+ julia> ex = 1 + (:x - 2 )
281+ :((+ )(1 , (- )(x, 2 )))
282+ ```
283+ How can we use SymbolicUtils.jl to convert ` ex ` to ` (-)(:x, 1) ` ? We simply implement ` istree ` ,
284+ ` operation ` , ` arguments ` and ` to_symbolic ` and we'll be off to the races:
285+ ``` julia
286+ using SymbolicUtils: Variable, istree, operation, arguments, to_symbolic
287+
288+ SymbolicUtils. istree (ex:: Expr ) = ex. head == :call
289+ SymbolicUtils. operation (ex:: Expr ) = ex. args[1 ]
290+ SymbolicUtils. arguments (ex:: Expr ) = ex. args[2 : end ]
291+ SymbolicUtils. to_symbolic (s:: Symbol ) = Variable (s)
292+
293+ julia> simplify (ex)
294+ (- 1 + x)
295+
296+ julia> dump (simplify (ex))
297+ Term{Any}
298+ f: + (function of type typeof (+ ))
299+ arguments: Array {Any} ((2 ,))
300+ 1 : Int64 - 1
301+ 2 : Variable{Any}
302+ name: Symbol x
303+ ```
304+ this thing returns a ` Term{Any} ` , but it's not hard to convert back to ` Expr ` :
305+ ``` julia
306+ to_expr (t:: Term ) = Expr (:call , operation (t), to_expr .(arguments (t))... )
307+ to_expr (x) = x
308+
309+ julia> to_expr (simplify (ex))
310+ :((+ )(- 1 , x))
311+
312+ julia> dump (ans)
313+ Expr
314+ head: Symbol call
315+ args: Array {Any} ((3 ,))
316+ 1 : + (function of type typeof (+ ))
317+ 2 : Int64 - 1
318+ 3 : Symbol x
319+ ```
320+
321+ Now suppose we actaully wanted all ` Symbol ` s to be treated as ` Real ` numbers. We can simply define
322+ ``` julia
323+ SymbolicUtils. symtype (s:: Symbol ) = Real
324+
325+ julia> dump (simplify (ex))
326+ Term{Real}
327+ f: + (function of type typeof (+ ))
328+ arguments: Array {Any} ((2 ,))
329+ 1 : Int64 - 1
330+ 2 : Variable{Real}
331+ name: Symbol x
332+ ```
333+ and now all our analysis is able to figure out that the ` Term ` s are ` Number ` s.
0 commit comments