Skip to content

Commit 6713fa0

Browse files
authored
Merge pull request #584 from JuliaSymbolics/ale/terminterface-new
New TermInterface
2 parents 8d8db32 + ed97a96 commit 6713fa0

19 files changed

+140
-119
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "SymbolicUtils"
22
uuid = "d1185830-fcd6-423d-90d6-eec64667417b"
33
authors = ["Shashi Gowda"]
4-
version = "1.5.1"
4+
version = "1.6.0"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
@@ -22,6 +22,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
2222
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
2323
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2424
SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5"
25+
TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c"
2526
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
2627
Unityper = "a7c27f48-0311-42f6-a7f8-2c11e75eb415"
2728

@@ -42,6 +43,7 @@ Setfield = "0.7, 0.8, 1"
4243
SpecialFunctions = "0.10, 1.0, 2"
4344
StaticArrays = "0.12, 1.0"
4445
SymbolicIndexingInterface = "0.3"
46+
TermInterface = "0.4"
4547
TimerOutputs = "0.5"
4648
Unityper = "0.1.2"
4749
julia = "1.3"

docs/src/api.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,6 @@ SymbolicUtils.Pow
1212
SymbolicUtils.promote_symtype
1313
```
1414

15-
## Interfacing
16-
17-
```@docs
18-
SymbolicUtils.istree
19-
SymbolicUtils.operation
20-
SymbolicUtils.arguments
21-
SymbolicUtils.similarterm
22-
```
23-
2415
## Rewriters
2516

2617
```@docs

docs/src/index.md

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,8 @@ g(2//5, g(1, β))
108108

109109
Symbolic expressions are of type `Term{T}`, `Add{T}`, `Mul{T}`, `Pow{T}` or `Div{T}` and denote some function call where one or more arguments are themselves such expressions or `Sym`s. See more about the representation [here](/representation/).
110110

111-
All the expression types support the following:
112-
113-
- `istree(x)` -- always returns `true` denoting, `x` is not a leaf node like Sym or a literal.
114-
- `operation(x)` -- the function being called
115-
- `arguments(x)` -- a vector of arguments
116-
- `symtype(x)` -- the "inferred" type (`T`)
117-
118-
See more on the interface [here](/interface)
119-
111+
All the expression types support the [TermInterface.jl](https://github.com/0x0f0f0f/TermInterface.jl) interface.
112+
Please refer to the package for the complete reference of the interface.
120113

121114
## Term rewriting
122115

src/SymbolicUtils.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,26 @@ $(DocStringExtensions.README)
44
module SymbolicUtils
55

66
using DocStringExtensions
7+
78
export @syms, term, showraw, hasmetadata, getmetadata, setmetadata
89

910
using Unityper
10-
11-
# Sym, Term,
12-
# Add, Mul and Pow
11+
using TermInterface
1312
using DataStructures
1413
using Setfield
1514
import Setfield: PropertyLens
1615
using SymbolicIndexingInterface
1716
import Base: +, -, *, /, //, \, ^, ImmutableDict
1817
using ConstructionBase
19-
include("interface.jl")
18+
using TermInterface
19+
import TermInterface: iscall, isexpr, issym, symtype, head, children,
20+
operation, arguments, metadata, maketerm
21+
22+
Base.@deprecate_binding istree iscall
23+
export istree, operation, arguments, unsorted_arguments, similarterm
24+
# Sym, Term,
25+
# Add, Mul and Pow
2026
include("types.jl")
21-
export istree, operation, arguments, similarterm
2227

2328
# Methods on symbolic objects
2429
using SpecialFunctions, NaNMath

src/code.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export toexpr, Assignment, (←), Let, Func, DestructuredArgs, LiteralExpr,
88

99
import ..SymbolicUtils
1010
import ..SymbolicUtils.Rewriters
11-
import SymbolicUtils: @matchable, BasicSymbolic, Sym, Term, istree, operation, arguments, issym,
11+
import SymbolicUtils: @matchable, BasicSymbolic, Sym, Term, iscall, operation, arguments, issym,
1212
symtype, similarterm, unsorted_arguments, metadata, isterm, term
1313

1414
##== state management ==##
@@ -162,7 +162,7 @@ end
162162
toexpr(O::Expr, st) = O
163163

164164
function substitute_name(O, st)
165-
if (issym(O) || istree(O)) && haskey(st.rewrites, O)
165+
if (issym(O) || iscall(O)) && haskey(st.rewrites, O)
166166
st.rewrites[O]
167167
else
168168
O
@@ -176,13 +176,13 @@ function toexpr(O, st)
176176
end
177177
O = substitute_name(O, st)
178178

179-
!istree(O) && return O
179+
!iscall(O) && return O
180180
op = operation(O)
181181
expr′ = function_to_expr(op, O, st)
182182
if expr′ !== nothing
183183
return expr′
184184
else
185-
!istree(O) && return O
185+
!iscall(O) && return O
186186
args = arguments(O)
187187
return Expr(:call, toexpr(op, st), map(x->toexpr(x, st), args)...)
188188
end
@@ -221,7 +221,7 @@ get_rewrites(args::DestructuredArgs) = ()
221221
function get_rewrites(args::Union{AbstractArray, Tuple})
222222
cflatten(map(get_rewrites, args))
223223
end
224-
get_rewrites(x) = istree(x) ? (x,) : ()
224+
get_rewrites(x) = iscall(x) ? (x,) : ()
225225
cflatten(x) = Iterators.flatten(x) |> collect
226226

227227
# Used in Symbolics
@@ -691,7 +691,7 @@ end
691691
@inline newsym(::Type{T}) where T = Sym{T}(gensym("cse"))
692692

693693
function _cse!(mem, expr)
694-
istree(expr) || return expr
694+
iscall(expr) || return expr
695695
op = _cse!(mem, operation(expr))
696696
args = map(Base.Fix1(_cse!, mem), arguments(expr))
697697
t = similarterm(expr, op, args)
@@ -742,7 +742,7 @@ end
742742

743743

744744
function cse_state!(state, t)
745-
!istree(t) && return t
745+
!iscall(t) && return t
746746
state[t] = Base.get!(state, t, 0) + 1
747747
foreach(x->cse_state!(state, x), unsorted_arguments(t))
748748
end
@@ -758,7 +758,7 @@ function cse_block!(assignments, counter, names, name, state, x)
758758
counter[] += 1
759759
return sym
760760
end
761-
elseif istree(x)
761+
elseif iscall(x)
762762
args = map(a->cse_block!(assignments, counter, names, name, state,a), unsorted_arguments(x))
763763
if isterm(x)
764764
return term(operation(x), args...)

src/inspect.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import AbstractTrees
22

33
const inspect_metadata = Ref{Bool}(false)
44
function AbstractTrees.nodevalue(x::Symbolic)
5-
istree(x) ? operation(x) : x
5+
iscall(x) ? operation(x) : isexpr(x) ? head(x) : x
66
end
77

88
function AbstractTrees.nodevalue(x::BasicSymbolic)
9-
str = if !istree(x)
9+
str = if !iscall(x)
1010
string(exprtype(x), "(", x, ")")
1111
elseif isadd(x)
1212
string(exprtype(x),
@@ -27,7 +27,7 @@ function AbstractTrees.nodevalue(x::BasicSymbolic)
2727
end
2828

2929
function AbstractTrees.children(x::Symbolic)
30-
istree(x) ? arguments(x) : ()
30+
iscall(x) ? arguments(x) : isexpr(x) ? children(x) : ()
3131
end
3232

3333
"""

src/interface.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"""
2-
istree(x)
2+
iscall(x)
33
44
Returns `true` if `x` is a term. If true, `operation`, `arguments`
55
must also be defined for `x` appropriately.
66
"""
7-
istree(x) = false
7+
iscall(x) = false
88

99
"""
1010
symtype(x)
@@ -29,7 +29,7 @@ issym(x) = false
2929
"""
3030
operation(x)
3131
32-
If `x` is a term as defined by `istree(x)`, `operation(x)` returns the
32+
If `x` is a term as defined by `iscall(x)`, `operation(x)` returns the
3333
head of the term if `x` represents a function call, for example, the head
3434
is the function being called.
3535
"""
@@ -38,14 +38,14 @@ function operation end
3838
"""
3939
arguments(x)
4040
41-
Get the arguments of `x`, must be defined if `istree(x)` is `true`.
41+
Get the arguments of `x`, must be defined if `iscall(x)` is `true`.
4242
"""
4343
function arguments end
4444

4545
"""
4646
unsorted_arguments(x::T)
4747
48-
If x is a term satisfying `istree(x)` and your term type `T` provides
48+
If x is a term satisfying `iscall(x)` and your term type `T` provides
4949
an optimized implementation for storing the arguments, this function can
5050
be used to retrieve the arguments when the order of arguments does not matter
5151
but the speed of the operation does.

src/matchers.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# 3. Callback: takes arguments Dictionary × Number of elements matched
77
#
88
function matcher(val::Any)
9-
istree(val) && return term_matcher(val)
9+
iscall(val) && return term_matcher(val)
1010
function literal_matcher(next, data, bindings)
1111
islist(data) && isequal(car(data), val) ? next(bindings, 1) : nothing
1212
end
@@ -89,7 +89,7 @@ function term_matcher(term)
8989
function term_matcher(success, data, bindings)
9090

9191
!islist(data) && return nothing
92-
!istree(car(data)) && return nothing
92+
!iscall(car(data)) && return nothing
9393

9494
function loop(term, bindings′, matchers′) # Get it to compile faster
9595
if !islist(matchers′)

src/ordering.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
function get_degrees(expr)
2121
if issym(expr)
2222
((Symbol(expr),) => 1,)
23-
elseif istree(expr)
23+
elseif iscall(expr)
2424
op = operation(expr)
2525
args = arguments(expr)
2626
if operation(expr) == (^) && args[2] isa Number
@@ -62,7 +62,7 @@ function lexlt(degs1, degs2)
6262
return false # they are equal
6363
end
6464

65-
_arglen(a) = istree(a) ? length(unsorted_arguments(a)) : 0
65+
_arglen(a) = iscall(a) ? length(unsorted_arguments(a)) : 0
6666

6767
function <(a::Tuple, b::Tuple)
6868
for (x, y) in zip(a, b)

src/polyform.jl

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ using Bijections
66
77
Abstracts a [MultivariatePolynomials.jl](https://juliaalgebra.github.io/MultivariatePolynomials.jl/stable/) as a SymbolicUtils expression and vice-versa.
88
9-
The SymbolicUtils term interface (`istree`, `operation, and `arguments`) works on PolyForm lazily:
9+
The SymbolicUtils term interface (`isexpr`/`iscall`, `operation, and `arguments`) works on PolyForm lazily:
1010
the `operation` and `arguments` are created by converting one level of arguments into SymbolicUtils expressions. They may further contain PolyForm within them.
1111
We use this to hold polynomials in memory while doing `simplify_fractions`.
1212
@@ -97,7 +97,7 @@ _isone(p::PolyForm) = isone(p.p)
9797
function polyize(x, pvar2sym, sym2term, vtype, pow, Fs, recurse)
9898
if x isa Number
9999
return x
100-
elseif istree(x)
100+
elseif iscall(x)
101101
if !(symtype(x) <: Number)
102102
error("Cannot convert $x of symtype $(symtype(x)) into a PolyForm")
103103
end
@@ -170,8 +170,10 @@ function PolyForm(x,
170170
PolyForm{symtype(x)}(p, pvar2sym, sym2term, metadata)
171171
end
172172

173-
istree(x::Type{<:PolyForm}) = true
174-
istree(x::PolyForm) = true
173+
isexpr(x::Type{<:PolyForm}) = true
174+
isexpr(x::PolyForm) = true
175+
iscall(x::Type{<:PolyForm}) = true
176+
iscall(x::PolyForm) = true
175177

176178
function similarterm(t::PolyForm, f, args, symtype; metadata=nothing)
177179
basic_similarterm(t, f, args, symtype; metadata=metadata)
@@ -181,6 +183,7 @@ function similarterm(::PolyForm, f::Union{typeof(*), typeof(+), typeof(^)},
181183
f(args...)
182184
end
183185

186+
head(::PolyForm) = PolyForm
184187
operation(x::PolyForm) = MP.nterms(x.p) == 1 ? (*) : (+)
185188

186189
function arguments(x::PolyForm{T}) where {T}
@@ -227,6 +230,7 @@ function arguments(x::PolyForm{T}) where {T}
227230
PolyForm{T}(t, x.pvar2sym, x.sym2term, nothing)) for t in ts]
228231
end
229232
end
233+
children(x::PolyForm) = [operation(x); arguments(x)]
230234

231235
Base.show(io::IO, x::PolyForm) = show_term(io, x)
232236

@@ -336,7 +340,7 @@ function simplify_fractions(x; polyform=false)
336340
end
337341

338342
function add_with_div(x, flatten=true)
339-
(!istree(x) || operation(x) != (+)) && return x
343+
(!iscall(x) || operation(x) != (+)) && return x
340344
aa = unsorted_arguments(x)
341345
!any(a->isdiv(a), aa) && return x # no rewrite necessary
342346

@@ -361,26 +365,26 @@ function flatten_fractions(x)
361365
end
362366

363367
function fraction_iszero(x)
364-
!istree(x) && return _iszero(x)
368+
!iscall(x) && return _iszero(x)
365369
ff = flatten_fractions(x)
366370
# fast path and then slow path
367371
any(_iszero, numerators(ff)) ||
368372
any(_iszeroexpand, numerators(ff))
369373
end
370374

371375
function fraction_isone(x)
372-
!istree(x) && return _isone(x)
376+
!iscall(x) && return _isone(x)
373377
_isone(simplify_fractions(flatten_fractions(x)))
374378
end
375379

376380
function needs_div_rules(x)
377381
(isdiv(x) && !(x.num isa Number) && !(x.den isa Number)) ||
378-
(istree(x) && operation(x) === (+) && count(has_div, unsorted_arguments(x)) > 1) ||
379-
(istree(x) && any(needs_div_rules, unsorted_arguments(x)))
382+
(iscall(x) && operation(x) === (+) && count(has_div, unsorted_arguments(x)) > 1) ||
383+
(iscall(x) && any(needs_div_rules, unsorted_arguments(x)))
380384
end
381385

382386
function has_div(x)
383-
return isdiv(x) || (istree(x) && any(has_div, unsorted_arguments(x)))
387+
return isdiv(x) || (iscall(x) && any(has_div, unsorted_arguments(x)))
384388
end
385389

386390
flatten_pows(xs) = map(xs) do x

0 commit comments

Comments
 (0)