Skip to content

Commit 4a926c6

Browse files
committed
revert interface.md to the old one
1 parent 134bc78 commit 4a926c6

File tree

1 file changed

+90
-6
lines changed

1 file changed

+90
-6
lines changed

page/interface.md

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,107 @@ where appropriate -->
77

88
# Interfacing with SymbolicUtils.jl
99

10-
<!-- TODO: document TermInterface.jl -->
11-
1210
\tableofcontents <!-- you can use \toc as well -->
1311

1412
This section is for Julia package developers who may want to use the `simplify` and rule rewriting system on their own expression types.
1513

1614
## Defining the interface
1715

18-
SymbolicUtils matchers can match any Julia object that implements an interface to traverse it as a tree. The interface in question, is defined in the [TermInterface.jl](https://github.com/JuliaSymbolics/TermInterface.jl) package. Its purpose is to provide a shared interface between various symbolic programming Julia packages.
16+
SymbolicUtils matchers can match any Julia object that implements an interface to traverse it as a tree.
1917

20-
In particular, you should define methods from TermInterface.jl for an expression tree type `T` with symbol types `S` to work
18+
In particular, the following methods should be defined for an expression tree type `T` with symbol types `S` to work
2119
with SymbolicUtils.jl
2220

23-
You can read the documentation of [TermInterface.jl](https://github.com/JuliaSymbolics/TermInterface.jl) on the [Github repository](https://github.com/JuliaSymbolics/TermInterface.jl).
21+
#### `istree(x::T)`
22+
23+
Check if `x` represents an expression tree. If returns true,
24+
it will be assumed that `operation(::T)` and `arguments(::T)`
25+
methods are defined. Definining these three should allow use
26+
of `simplify` on custom types. Optionally `symtype(x)` can be
27+
defined to return the expected type of the symbolic expression.
28+
29+
#### `operation(x::T)`
30+
31+
Returns the operation (a function object) performed by an expression
32+
tree. Called only if `istree(::T)` is true. Part of the API required
33+
for `simplify` to work. Other required methods are `arguments` and `istree`
34+
35+
#### `arguments(x::T)`
36+
37+
Returns the arguments (a `Vector`) for an expression tree.
38+
Called only if `istree(x)` is `true`. Part of the API required
39+
for `simplify` to work. Other required methods are `operation` and `istree`
40+
41+
In addition, the methods for `Base.hash` and `Base.isequal` should also be implemented by the types for the purposes of substitution and equality matching respectively.
42+
43+
#### `similarterm(t::MyType, f, args[, T])`
44+
45+
Construct a new term with the operation `f` and arguments `args`, the term should be similar to `t` in type. if `t` is a `Term` object a new Term is created with the same symtype as `t`. If not, the result is computed as `f(args...)`. Defining this method for your term type will reduce any performance loss in performing `f(args...)` (esp. the splatting, and redundant type computation). T is the symtype of the output term. You can use `promote_symtype` to infer this type.
46+
47+
The below two functions are internal to SymbolicUtils
48+
49+
### Optional
50+
51+
#### `symtype(x)`
52+
53+
The supposed type of values in the domain of x. Tracing tools can use this type to
54+
pick the right method to run or analyse code.
55+
56+
This defaults to `typeof(x)` if `x` is numeric, or `Any` otherwise.
57+
For the types defined in this package, namely `T<:Symbolic{S}` it is `S`.
2458

25-
## SymbolicUtils.jl only methods
59+
Define this for your symbolic types if you want `simplify` to apply rules
60+
specific to numbers (such as commutativity of multiplication). Or such
61+
rules that may be implemented in the future.
2662

2763
#### `promote_symtype(f, arg_symtypes...)`
2864

2965
Returns the appropriate output type of applying `f` on arguments of type `arg_symtypes`.
66+
67+
## Example
68+
69+
Suppose you were feeling the temptations of type piracy and wanted to make a quick and dirty
70+
symbolic library built on top of Julia's `Expr` type, e.g.
71+
72+
```julia:piracy1
73+
for f ∈ [:+, :-, :*, :/, :^] #Note, this is type piracy!
74+
@eval begin
75+
Base.$f(x::Union{Expr, Symbol}, y::Number) = Expr(:call, $f, x, y)
76+
Base.$f(x::Number, y::Union{Expr, Symbol}) = Expr(:call, $f, x, y)
77+
Base.$f(x::Union{Expr, Symbol}, y::Union{Expr, Symbol}) = (Expr(:call, $f, x, y))
78+
end
79+
end
80+
81+
82+
ex = 1 + (:x - 2)
83+
```
84+
85+
86+
How can we use SymbolicUtils.jl to convert `ex` to `(-)(:x, 1)`? We simply implement `istree`,
87+
`operation`, `arguments` and we'll be able to do rule-based rewriting on `Expr`s:
88+
```julia:piracy2
89+
using SymbolicUtils
90+
91+
SymbolicUtils.istree(ex::Expr) = ex.head == :call
92+
SymbolicUtils.operation(ex::Expr) = ex.args[1]
93+
SymbolicUtils.arguments(ex::Expr) = ex.args[2:end]
94+
95+
@rule(~x => ~x - 1)(ex)
96+
```
97+
98+
However, this is not enough to get SymbolicUtils to use its own algebraic simplification system on `Expr`s:
99+
```julia:piracy3
100+
simplify(ex)
101+
```
102+
103+
The reason that the expression was not simplified is that the expression tree is untyped, so SymbolicUtils
104+
doesn't know what rules to apply to the expression. To mimic the behaviour of most computer algebra
105+
systems, the simplest thing to do would be to assume that all `Expr`s are of type `Number`:
106+
107+
```julia:piracy4
108+
SymbolicUtils.symtype(s::Expr) = Number
109+
110+
simplify(ex)
111+
```
112+
113+
Now SymbolicUtils is able to apply the `Number` simplification rule to `Expr`.

0 commit comments

Comments
 (0)