20
20
for op in [:+ , :- , :(== )]
21
21
@eval Base.$ op (p1:: APL , p2:: APL ) = $ op (promote (p1, p2)... )
22
22
end
23
+ # Promotion between `I` and `1` is `Any`.
24
+ # Promotion between `I` and `2I` is `UniformScaling`.
25
+ for op in [:+ , :- ]
26
+ @eval Base.$ op (p1:: APL , p2:: APL{<:LinearAlgebra.UniformScaling} ) = $ op (p1, mapcoefficientsnz (J -> J. λ, p2))
27
+ @eval Base.$ op (p1:: APL{<:LinearAlgebra.UniformScaling} , p2:: APL ) = $ op (mapcoefficientsnz (J -> J. λ, p1), p2)
28
+ @eval Base.$ op (p1:: APL{<:LinearAlgebra.UniformScaling} , p2:: APL{<:LinearAlgebra.UniformScaling} ) = $ op (mapcoefficientsnz (J -> J. λ, p1), p2)
29
+ end
23
30
Base. isapprox (p1:: APL , p2:: APL ; kwargs... ) = isapprox (promote (p1, p2)... ; kwargs... )
24
31
25
32
# @eval $op(p::APL, α) = $op(promote(p, α)...) would be less efficient
26
33
for (op, fun) in [(:+ , :plusconstant ), (:- , :minusconstant ), (:* , :multconstant ), (:(== ), :eqconstant )]
27
34
@eval Base.$ op (p:: APL , α) = $ fun (p, α)
28
35
@eval Base.$ op (α, p:: APL ) = $ fun (α, p)
29
36
end
37
+ # Fix ambiguity between above methods and methods in MA
38
+ Base.:+ (:: MA.Zero , p:: APL ) = MA. copy_if_mutable (p)
39
+ Base.:+ (p:: APL , :: MA.Zero ) = MA. copy_if_mutable (p)
40
+ constant_function (:: typeof (+ )) = plusconstant
41
+ constant_function (:: typeof (- )) = minusconstant
42
+ MA. mutable_operate! (op:: Union{typeof(+), typeof(-)} , p:: APL , α) = MA. mutable_operate! (constant_function (op), p, α)
43
+ MA. mutable_operate_to! (output:: AbstractPolynomial , op:: typeof (* ), α, p:: APL ) = MA. mutable_operate_to! (output, multconstant, α, p)
44
+ MA. mutable_operate_to! (output:: AbstractPolynomial , op:: typeof (* ), p:: APL , α) = MA. mutable_operate_to! (output, multconstant, p, α)
45
+
46
+ function polynomial_merge! (
47
+ n1:: Int , n2:: Int , get1:: Function , get2:: Function ,
48
+ set:: Function , push:: Function , compare_monomials:: Function ,
49
+ combine:: Function , keep:: Function , resize:: Function )
50
+ buffer = nothing
51
+ i = j = k = 1
52
+ # Invariant:
53
+ # The terms p[0] -> p[k-1] are sorted and are smaller than the remaining terms.
54
+ # The terms p[k] -> p[i-1] are garbage.
55
+ # The terms p[i] -> p[end] are sorted and still need to be added.
56
+ # The terms q[j] -> p[end] are sorted and still need to be added.
57
+ # If `buffer` is not empty:
58
+ # The terms in `buffer` are sorted and still need to be added.
59
+ # Moreover, they are smaller than the terms p[i] -> p[end].
60
+ while i <= n1 && j <= n2
61
+ @assert buffer === nothing || isempty (buffer)
62
+ comp = compare_monomials (i, j)
63
+ if comp > 0
64
+ if k == i
65
+ t0 = get1 (i)
66
+ if buffer === nothing
67
+ buffer = DataStructures. Queue {typeof(t0)} ()
68
+ end
69
+ DataStructures. enqueue! (buffer, t0)
70
+ i += 1
71
+ end
72
+ set (k, get2 (j))
73
+ j += 1
74
+ k += 1
75
+ elseif iszero (comp)
76
+ combine (i, j)
77
+ if keep (i)
78
+ if k != i
79
+ @assert k < i
80
+ set (k, get1 (i))
81
+ end
82
+ k += 1
83
+ end
84
+ i += 1
85
+ j += 1
86
+ else
87
+ if k != i
88
+ set (k, get1 (i))
89
+ end
90
+ i += 1
91
+ k += 1
92
+ end
93
+ while buffer != = nothing && ! isempty (buffer) && j <= n2
94
+ @assert i == k
95
+ t = DataStructures. front (buffer)
96
+ comp = compare_monomials (t, j)
97
+ if comp >= 0
98
+ if comp > 0
99
+ t = get2 (j)
100
+ else
101
+ t = combine (t, j)
102
+ end
103
+ j += 1
104
+ end
105
+ if comp <= 0
106
+ DataStructures. dequeue! (buffer)
107
+ end
108
+ # if `comp` is zero, we called `combine` so `t`
109
+ # might not be kept. If `comp` is not zero, we
110
+ # skip the `keep` call that might be costly.
111
+ if iszero (comp) && ! keep (t)
112
+ continue
113
+ end
114
+ if k <= n1
115
+ DataStructures. enqueue! (buffer, get1 (i))
116
+ set (k, t)
117
+ else
118
+ push (t)
119
+ n1 += 1
120
+ end
121
+ i += 1
122
+ k += 1
123
+ end
124
+ end
125
+ if buffer != = nothing && ! isempty (buffer)
126
+ @assert j == n2 + 1
127
+ @assert i == k
128
+ n = length (buffer)
129
+ resize (n1 + n)
130
+ for k in n1: - 1 : i
131
+ set (k + n, get1 (k))
132
+ end
133
+ for k in i: (i + n - 1 )
134
+ set (k, DataStructures. dequeue! (buffer))
135
+ end
136
+ n1 += n
137
+ else
138
+ len = (k - 1 ) + (n2 - (j - 1 )) + (n1 - (i - 1 ))
139
+ if n1 < len
140
+ resize (len)
141
+ end
142
+ while j <= n2
143
+ set (k, get2 (j))
144
+ j += 1
145
+ k += 1
146
+ end
147
+ @assert j == n2 + 1
148
+ while i <= n1
149
+ set (k, get1 (i))
150
+ i += 1
151
+ k += 1
152
+ end
153
+ if len < n1
154
+ resize (len)
155
+ end
156
+ @assert i == n1 + 1
157
+ @assert k == len + 1
158
+ end
159
+ return
160
+ end
161
+
30
162
31
- MA. mutable_operate! (op:: Union{typeof(+), typeof(-)} , p:: AbstractPolynomial , q:: AbstractPolynomial ) = MA. mutable_operate_to! (p, op, p, q)
163
+ # MA.mutable_operate!(op::Union{typeof(+), typeof(-)}, p::AbstractPolynomial, q::AbstractPolynomial) = MA.mutable_operate_to!(p, op, p, q)
32
164
MA. mutable_operate! (op:: Union{typeof(+), typeof(-)} , p:: AbstractPolynomial , q:: AbstractPolynomialLike ) = MA. mutable_operate! (op, p, polynomial (q))
33
165
34
166
# Special case AbstractArrays of APLs
@@ -41,6 +173,18 @@ for op in [:+, :-, :*]
41
173
end
42
174
Base.:/ (A:: AbstractArray{<:APL} , p:: APL ) = map (f -> f / p, A)
43
175
176
+ function mul_to_terms! (ts:: Vector{<:AbstractTerm} , p1:: APL , p2:: APL )
177
+ for t1 in terms (p1)
178
+ for t2 in terms (p2)
179
+ push! (ts, t1 * t2)
180
+ end
181
+ end
182
+ return ts
183
+ end
184
+ function Base.:* (p:: AbstractPolynomial , q:: AbstractPolynomial )
185
+ polynomial (mul_to_terms! (MA. promote_operation (* , termtype (p), termtype (q))[], p, q))
186
+ end
187
+
44
188
Base. isapprox (p:: APL , α; kwargs... ) = isapprox (promote (p, α)... ; kwargs... )
45
189
Base. isapprox (α, p:: APL ; kwargs... ) = isapprox (promote (p, α)... ; kwargs... )
46
190
@@ -52,10 +196,16 @@ Base.:*(p::Union{APL, RationalPoly}) = p
52
196
53
197
# Avoid adding a zero constant that might artificially increase the Newton polytope
54
198
# Need to add polynomial conversion for type stability
55
- plusconstant (p:: APL{S} , α:: T ) where {S, T} = iszero (α) ? polynomial ( p, Base. promote_op (+ , S, T)) : p + constantterm (α, p)
56
- plusconstant (α:: S , p:: APL{T} ) where {S, T} = iszero (α) ? polynomial ( p, Base. promote_op (+ , S, T)) : constantterm (α, p) + p
57
- minusconstant (p:: APL{S} , α:: T ) where {S, T} = iszero (α) ? polynomial ( p, Base. promote_op (- , S, T)) : p - constantterm (α, p)
58
- minusconstant (α:: S , p:: APL{T} ) where {S, T} = iszero (α) ? polynomial (- p, Base. promote_op (- , S, T)) : constantterm (α, p) - p
199
+ plusconstant (p:: APL{S} , α:: T ) where {S, T} = iszero (α) ? polynomial ( p, MA. promote_operation (+ , S, T)) : p + constantterm (α, p)
200
+ plusconstant (α:: S , p:: APL{T} ) where {S, T} = iszero (α) ? polynomial ( p, MA. promote_operation (+ , S, T)) : constantterm (α, p) + p
201
+ function MA. mutable_operate! (:: typeof (plusconstant), p:: APL , α)
202
+ if ! iszero (α)
203
+ MA. mutable_operate! (+ , p, constantterm (α, p))
204
+ end
205
+ return p
206
+ end
207
+ minusconstant (p:: APL{S} , α:: T ) where {S, T} = iszero (α) ? polynomial ( p, MA. promote_operation (- , S, T)) : p - constantterm (α, p)
208
+ minusconstant (α:: S , p:: APL{T} ) where {S, T} = iszero (α) ? polynomial (- p, MA. promote_operation (- , S, T)) : constantterm (α, p) - p
59
209
60
210
# Coefficients and variables commute
61
211
multconstant (α, v:: AbstractVariable ) = multconstant (α, monomial (v)) # TODO linear term
@@ -64,7 +214,7 @@ multconstant(m::AbstractMonomialLike, α) = multconstant(α, m)
64
214
_multconstant (α, f, t:: AbstractTermLike ) = mapcoefficientsnz (f, t)
65
215
function _multconstant (α:: T , f, p:: AbstractPolynomial{S} ) where {S, T}
66
216
if iszero (α)
67
- zero (polynomialtype (p, Base . promote_op (* , T, S)))
217
+ zero (polynomialtype (p, MA . promote_operation (* , T, S)))
68
218
else
69
219
mapcoefficientsnz (f, p)
70
220
end
@@ -74,6 +224,22 @@ _multconstant(α, f, p::AbstractPolynomialLike) = _multconstant(α, f, polynomia
74
224
multconstant (α, p:: AbstractPolynomialLike ) = _multconstant (α, β -> α* β, p)
75
225
multconstant (p:: AbstractPolynomialLike , α) = _multconstant (α, β -> β* α, p)
76
226
227
+ function mapcoefficientsnz_to! end
228
+
229
+ function _multconstant_to! (output, α, f, p)
230
+ if iszero (α)
231
+ MA. mutable_operate! (zero, output)
232
+ else
233
+ mapcoefficientsnz_to! (output, f, p)
234
+ end
235
+ end
236
+ function MA. mutable_operate_to! (output, :: typeof (multconstant), p:: APL , α)
237
+ _multconstant_to! (output, α, β -> β* α, p)
238
+ end
239
+ function MA. mutable_operate_to! (output, :: typeof (multconstant), α, p:: APL )
240
+ _multconstant_to! (output, α, β -> α* β, p)
241
+ end
242
+
77
243
MA. mutable_operate_to! (output:: AbstractMonomial , :: typeof (* ), m1:: AbstractMonomialLike , m2:: AbstractMonomialLike ) = mapexponents_to! (output, + , m1, m2)
78
244
MA. mutable_operate! (:: typeof (* ), m1:: AbstractMonomial , m2:: AbstractMonomialLike ) = mapexponents! (+ , m1, m2)
79
245
Base.:* (m1:: AbstractMonomialLike , m2:: AbstractMonomialLike ) = mapexponents (+ , m1, m2)
100
266
for op in [:+ , :- ]
101
267
@eval begin
102
268
Base.$ op (t1:: AbstractTermLike , t2:: AbstractTermLike ) = $ op (term (t1), term (t2))
103
- Base.$ op (t1:: AbstractTerm , t2:: AbstractTerm ) = $ op (promote (t1, t2)... )
269
+ Base.$ op (t1:: AbstractTerm , t2:: AbstractTerm ) = $ op (_promote_terms (t1, t2)... )
104
270
function Base. $op (t1:: TT , t2:: TT ) where {T, TT <: AbstractTerm{T} }
105
- S = Base . promote_op ($ op, T, T)
271
+ S = MA . promote_operation ($ op, T, T)
106
272
# t1 > t2 would compare the coefficient in case the monomials are equal
107
273
# and it will throw a MethodError in case the coefficients are not comparable
108
274
if monomial (t1) == monomial (t2)
@@ -115,6 +281,18 @@ for op in [:+, :-]
115
281
end
116
282
end
117
283
end
284
+ _promote_terms (t1, t2) = promote (t1, t2)
285
+ # Promotion between `I` and `1` is `Any`.
286
+ _promote_terms (t1:: AbstractTerm , t2:: AbstractTerm{<:LinearAlgebra.UniformScaling} ) = _promote_terms (t1, coefficient (t2). λ * monomial (t2))
287
+ _promote_terms (t1:: AbstractTerm{<:LinearAlgebra.UniformScaling} , t2:: AbstractTerm ) = _promote_terms (coefficient (t1). λ * monomial (t1), t2)
288
+ # Promotion between `I` and `2I` is `UniformScaling`, not `UniformScaling{Int}`.
289
+ function _promote_terms (t1:: AbstractTerm{LinearAlgebra.UniformScaling{S}} , t2:: AbstractTerm{LinearAlgebra.UniformScaling{T}} ) where {S<: Number , T<: Number }
290
+ U = LinearAlgebra. UniformScaling{promote_type (S, T)}
291
+ _promote_terms (MA. scaling_convert (U, coefficient (t1)) * monomial (t1), MA. scaling_convert (U, coefficient (t2)) * monomial (t2))
292
+ end
293
+ function _promote_terms (t1:: AbstractTerm{LinearAlgebra.UniformScaling{T}} , t2:: AbstractTerm{LinearAlgebra.UniformScaling{T}} ) where T<: Number
294
+ return promote (t1, t2)
295
+ end
118
296
119
297
LinearAlgebra. adjoint (v:: AbstractVariable ) = v
120
298
LinearAlgebra. adjoint (m:: AbstractMonomial ) = m
@@ -132,6 +310,9 @@ LinearAlgebra.dot(p1::AbstractPolynomialLike, p2::AbstractPolynomialLike) = p1'
132
310
LinearAlgebra. dot (x, p:: AbstractPolynomialLike ) = x' * p
133
311
LinearAlgebra. dot (p:: AbstractPolynomialLike , x) = p' * x
134
312
313
+ LinearAlgebra. symmetric_type (PT:: Type{<:APL} ) = PT
314
+ LinearAlgebra. symmetric (p:: APL , :: Symbol ) = p
315
+
135
316
# Amazingly, this works! Thanks, StaticArrays.jl!
136
317
"""
137
318
Convert a tuple of variables into a static vector to allow array-like usage.
@@ -146,15 +327,15 @@ Base.:^(x::AbstractPolynomialLike, p::Integer) = Base.power_by_squaring(x, p)
146
327
function MA. mutable_operate_to! (output:: AbstractPolynomial , :: typeof (MA. add_mul), x, args:: Vararg{Any, N} ) where N
147
328
return MA. mutable_operate_to! (output, + , x, * (args... ))
148
329
end
149
- function MA. mutable_operate! (:: typeof (MA. add_mul), x, args:: Vararg{Any, N} ) where N
150
- return MA. mutable_operate! (+ , x, * (args... ))
330
+ function MA. mutable_operate! (:: typeof (MA. add_mul), x, y, z, args:: Vararg{Any, N} ) where N
331
+ return MA. mutable_operate! (+ , x, * (y, z, args... ))
151
332
end
152
- MA. buffer_for (:: typeof (MA. add_mul), :: Type{<:AbstractPolynomial} , args:: Vararg{Any , N} ) where {N} = MA. promote_operation (* , args... )
153
- function MA. mutable_buffered_operate_to! (buffer:: AbstractPolynomial , output:: AbstractPolynomial , :: typeof (MA. add_mul), x, args:: Vararg{Any, N} ) where N
154
- product = MA. operate_to! (buffer, * , args... )
333
+ MA. buffer_for (:: typeof (MA. add_mul), :: Type{<:AbstractPolynomial} , args:: Vararg{Type , N} ) where {N} = zero ( MA. promote_operation (* , args... ) )
334
+ function MA. mutable_buffered_operate_to! (buffer:: AbstractPolynomial , output:: AbstractPolynomial , :: typeof (MA. add_mul), x, y, z, args:: Vararg{Any, N} ) where N
335
+ product = MA. operate_to! (buffer, * , y, z, args... )
155
336
return MA. mutable_operate_to! (output, + , x, product)
156
337
end
157
- function MA. mutable_buffered_operate! (buffer:: AbstractPolynomial , :: typeof (MA. add_mul), x, args:: Vararg{Any, N} ) where N
158
- product = MA. operate_to! (buffer, * , args... )
338
+ function MA. mutable_buffered_operate! (buffer:: AbstractPolynomial , :: typeof (MA. add_mul), x, y, z, args:: Vararg{Any, N} ) where N
339
+ product = MA. operate_to! (buffer, * , y, z, args... )
159
340
return MA. mutable_operate! (+ , x, product)
160
341
end
0 commit comments