@@ -30,52 +30,54 @@ For a sum expression, returns the `get_degrees()` result for term with the highe
30
30
See also `monomial_lt` and `lexlt`.
31
31
"""
32
32
function get_degrees (expr)
33
- res = _get_degrees (expr)
33
+ degs_cache = Dict ()
34
+ res = _get_degrees (expr, degs_cache)
34
35
if res isa AbstractVector
35
36
return Tuple (res)
36
37
else
37
38
return res
38
39
end
39
40
end
40
41
41
- function _get_degrees (expr)
42
+ function _get_degrees (expr, degs_cache :: AbstractDict )
42
43
if issym (expr)
43
- return (( Symbol (expr),) => 1 ,)
44
+ return get! (() -> (( Symbol (expr),) => 1 ,), degs_cache, expr )
44
45
elseif iscall (expr)
45
46
# operation-specific degree handling
46
- return _get_degrees (operation (expr), expr)
47
+ return _get_degrees (operation (expr), expr, degs_cache )
47
48
else
48
49
return () # skip numbers and unsupported expressions
49
50
end
50
51
end
51
52
52
53
# fallback for unsupported operation
53
- _get_degrees (:: Any , expr) =
54
+ _get_degrees (:: Any , expr, degs_cache ) =
54
55
((Symbol (" zzzzzzz" , hash (expr)),) => 1 ,)
55
56
56
57
_getindex_symbol (arr, i) = Symbol (arr[i])
57
58
58
- function _get_degrees (:: typeof (getindex), expr)
59
+ function _get_degrees (:: typeof (getindex), expr, degs_cache )
59
60
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)
61
63
end
62
64
63
- function _get_degrees (:: typeof (* ), expr)
65
+ function _get_degrees (:: typeof (* ), expr, degs_cache )
64
66
args = arguments (expr)
65
67
ds = sizehint! (Vector {Any} (), length (args))
66
68
for arg in args
67
- degs = _get_degrees (arg)
69
+ degs = _get_degrees (arg, degs_cache )
68
70
append! (ds, degs)
69
71
end
70
72
return sort! (ds)
71
73
end
72
74
73
- function _get_degrees (:: typeof (+ ), expr)
75
+ function _get_degrees (:: typeof (+ ), expr, degs_cache )
74
76
# among the terms find the best in terms of monomial_lt
75
77
sel_degs = ()
76
78
sel_degsum = 0
77
79
for arg in arguments (expr)
78
- degs = _get_degrees (arg)
80
+ degs = _get_degrees (arg, degs_cache )
79
81
degsum = sum (last, degs, init= 0 )
80
82
if (sel_degs == ()) || (degsum > sel_degsum) ||
81
83
(degsum == sel_degsum && lexlt (degs, sel_degs))
@@ -85,10 +87,10 @@ function _get_degrees(::typeof(+), expr)
85
87
return sel_degs
86
88
end
87
89
88
- function _get_degrees (:: typeof (^ ), expr)
90
+ function _get_degrees (:: typeof (^ ), expr, degs_cache )
89
91
base_expr, pow_expr = arguments (expr)
90
92
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)
92
94
(base => pow * pow_expr)
93
95
end
94
96
if pow_expr < 0 && length (degs) > 1
@@ -99,23 +101,23 @@ function _get_degrees(::typeof(^), expr)
99
101
return degs
100
102
else
101
103
# expression in the power argument is not supported
102
- return _get_degrees (nothing , expr)
104
+ return _get_degrees (nothing , expr, degs_cache )
103
105
end
104
106
end
105
107
106
- function _get_degrees (:: typeof (/ ), expr)
108
+ function _get_degrees (:: typeof (/ ), expr, degs_cache )
107
109
nom_expr, denom_expr = arguments (expr)
108
110
if denom_expr isa Number # constant denominator
109
- return _get_degrees (nom_expr)
111
+ return _get_degrees (nom_expr, degs_cache )
110
112
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)
112
114
(base => - pow)
113
115
end
114
116
isa (degs, AbstractVector) || (degs = collect (degs))
115
117
return sort! (degs)
116
118
else
117
119
# 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 )
119
121
end
120
122
end
121
123
0 commit comments