Skip to content

Commit bcec2ee

Browse files
author
Alexey Stukalov
committed
get_degees(): cache term syms
For long polynomials get_degree(term) causes most allocations and time. Cashing get_degree(term) to speeds it up and reduces memory footprint.
1 parent 929eeeb commit bcec2ee

File tree

1 file changed

+20
-18
lines changed

1 file changed

+20
-18
lines changed

src/ordering.jl

+20-18
Original file line numberDiff line numberDiff line change
@@ -30,52 +30,54 @@ For a sum expression, returns the `get_degrees()` result for term with the highe
3030
See also `monomial_lt` and `lexlt`.
3131
"""
3232
function get_degrees(expr)
33-
res = _get_degrees(expr)
33+
degs_cache = Dict()
34+
res = _get_degrees(expr, degs_cache)
3435
if res isa AbstractVector
3536
return Tuple(res)
3637
else
3738
return res
3839
end
3940
end
4041

41-
function _get_degrees(expr)
42+
function _get_degrees(expr, degs_cache::AbstractDict)
4243
if issym(expr)
43-
return ((Symbol(expr),) => 1,)
44+
return get!(() -> ((Symbol(expr),) => 1,), degs_cache, expr)
4445
elseif iscall(expr)
4546
# operation-specific degree handling
46-
return _get_degrees(operation(expr), expr)
47+
return _get_degrees(operation(expr), expr, degs_cache)
4748
else
4849
return () # skip numbers and unsupported expressions
4950
end
5051
end
5152

5253
# fallback for unsupported operation
53-
_get_degrees(::Any, expr) =
54+
_get_degrees(::Any, expr, degs_cache) =
5455
((Symbol("zzzzzzz", hash(expr)),) => 1,)
5556

5657
_getindex_symbol(arr, i) = Symbol(arr[i])
5758

58-
function _get_degrees(::typeof(getindex), expr)
59+
function _get_degrees(::typeof(getindex), expr, degs_cache)
5960
args = arguments(expr)
60-
@inbounds return (ntuple(Base.Fix1(_getindex_symbol, args), length(args)) => 1,)
61+
@inbounds return get!(() -> (ntuple(Base.Fix1(_getindex_symbol, args), length(args)) => 1,),
62+
degs_cache, expr)
6163
end
6264

63-
function _get_degrees(::typeof(*), expr)
65+
function _get_degrees(::typeof(*), expr, degs_cache)
6466
args = arguments(expr)
6567
ds = sizehint!(Vector{Any}(), length(args))
6668
for arg in args
67-
degs = _get_degrees(arg)
69+
degs = _get_degrees(arg, degs_cache)
6870
append!(ds, degs)
6971
end
7072
return sort!(ds)
7173
end
7274

73-
function _get_degrees(::typeof(+), expr)
75+
function _get_degrees(::typeof(+), expr, degs_cache)
7476
# among the terms find the best in terms of monomial_lt
7577
sel_degs = ()
7678
sel_degsum = 0
7779
for arg in arguments(expr)
78-
degs = _get_degrees(arg)
80+
degs = _get_degrees(arg, degs_cache)
7981
degsum = sum(last, degs, init=0)
8082
if (sel_degs == ()) || (degsum > sel_degsum) ||
8183
(degsum == sel_degsum && lexlt(degs, sel_degs))
@@ -85,10 +87,10 @@ function _get_degrees(::typeof(+), expr)
8587
return sel_degs
8688
end
8789

88-
function _get_degrees(::typeof(^), expr)
90+
function _get_degrees(::typeof(^), expr, degs_cache)
8991
base_expr, pow_expr = arguments(expr)
9092
if pow_expr isa Number
91-
@inbounds degs = map(_get_degrees(base_expr)) do (base, pow)
93+
@inbounds degs = map(_get_degrees(base_expr, degs_cache)) do (base, pow)
9294
(base => pow * pow_expr)
9395
end
9496
if pow_expr < 0 && length(degs) > 1
@@ -99,23 +101,23 @@ function _get_degrees(::typeof(^), expr)
99101
return degs
100102
else
101103
# expression in the power argument is not supported
102-
return _get_degrees(nothing, expr)
104+
return _get_degrees(nothing, expr, degs_cache)
103105
end
104106
end
105107

106-
function _get_degrees(::typeof(/), expr)
108+
function _get_degrees(::typeof(/), expr, degs_cache)
107109
nom_expr, denom_expr = arguments(expr)
108110
if denom_expr isa Number # constant denominator
109-
return _get_degrees(nom_expr)
111+
return _get_degrees(nom_expr, degs_cache)
110112
elseif nom_expr isa Number # constant nominator
111-
@inbounds degs = map(_get_degrees(denom_expr)) do (base, pow)
113+
@inbounds degs = map(_get_degrees(denom_expr, degs_cache)) do (base, pow)
112114
(base => -pow)
113115
end
114116
isa(degs, AbstractVector) || (degs = collect(degs))
115117
return sort!(degs)
116118
else
117119
# TODO expressions in both nom and denom are not yet supported
118-
return _get_degrees(nothing, expr)
120+
return _get_degrees(nothing, expr, degs_cache)
119121
end
120122
end
121123

0 commit comments

Comments
 (0)