| Line | Exclusive | Inclusive | Code |
|---|---|---|---|
| 1 | Base.one(::Type{P}) where {C, T, P <: Polynomial{C, T}} = Polynomial(one(T)) | ||
| 2 | Base.one(p::Polynomial) = one(typeof(p)) | ||
| 3 | |||
| 4 | Base.zero(::Type{Polynomial{C, T, A}}) where {C, T, A} = Polynomial(A()) | ||
| 5 | Base.zero(t::PolynomialLike) = zero(typeof(t)) | ||
| 6 | |||
| 7 | combine(t1::Term, t2::Term) = combine(promote(t1, t2)...) | ||
| 8 | combine(t1::T, t2::T) where {T <: Term} = Term(t1.coefficient + t2.coefficient, t1.monomial) | ||
| 9 | compare(t1::Term, t2::Term) = monomial(t1) > monomial(t2) | ||
| 10 | |||
| 11 | # Graded Lexicographic order | ||
| 12 | # First compare total degree, then lexicographic order | ||
| 13 | function isless(m1::Monomial{V}, m2::Monomial{V}) where {V} | ||
| 14 | 14 (2 %) |
14 (100 %)
samples spent calling
degree
d1 = degree(m1)
|
|
| 15 | 123 (15 %) |
123 (100 %)
samples spent calling
degree
d2 = degree(m2)
|
|
| 16 | 53 (6 %) |
53 (100 %)
samples spent calling
<
if d1 < d2
|
|
| 17 | return true | ||
| 18 | 9 (1 %) |
9 (100 %)
samples spent calling
>
elseif d1 > d2
|
|
| 19 | return false | ||
| 20 | else | ||
| 21 | 10 (1 %) | return exponents(m1) < exponents(m2) | |
| 22 | end | ||
| 23 | end | ||
| 24 | function grlex(m1::Monomial{V}, m2::Monomial{V}) where {V} | ||
| 25 | d1 = degree(m1) | ||
| 26 | d2 = degree(m2) | ||
| 27 | if d1 != d2 | ||
| 28 | return d1 - d2 | ||
| 29 | else | ||
| 30 | if exponents(m1) == exponents(m2) | ||
| 31 | return 0 | ||
| 32 | elseif exponents(m1) < exponents(m2) | ||
| 33 | return -1 | ||
| 34 | else | ||
| 35 | return 1 | ||
| 36 | end | ||
| 37 | end | ||
| 38 | end | ||
| 39 | grlex(m1::Monomial, m2::Monomial) = grlex(promote(m1, m2)...) | ||
| 40 | |||
| 41 | jointerms(terms1::AbstractArray{<:Term}, terms2::AbstractArray{<:Term}) = mergesorted(terms1, terms2, compare, combine) | ||
| 42 | function jointerms!(output::AbstractArray{<:Term}, terms1::AbstractArray{<:Term}, terms2::AbstractArray{<:Term}) | ||
| 43 | resize!(output, length(terms1) + length(terms2)) | ||
| 44 | Sequences.mergesorted!(output, terms1, terms2, compare, combine) | ||
| 45 | end | ||
| 46 | |||
| 47 | (+)(p1::Polynomial, p2::Polynomial) = Polynomial(jointerms(terms(p1), terms(p2))) | ||
| 48 | (+)(p1::Polynomial, p2::Polynomial{<:UniformScaling}) = p1 + MP.mapcoefficientsnz(J -> J.λ, p2) | ||
| 49 | (+)(p1::Polynomial{<:UniformScaling}, p2::Polynomial) = MP.mapcoefficientsnz(J -> J.λ, p1) + p2 | ||
| 50 | (+)(p1::Polynomial{<:UniformScaling}, p2::Polynomial{<:UniformScaling}) = MP.mapcoefficientsnz(J -> J.λ, p1) + p2 | ||
| 51 | function MA.mutable_operate_to!(result::Polynomial, ::typeof(+), p1::Polynomial, p2::Polynomial) | ||
| 52 | if result === p1 || result === p2 | ||
| 53 | error("Cannot call `mutable_operate_to!(output, +, p, q)` with `output` equal to `p` or `q`, call `mutable_operate!` instead.") | ||
| 54 | end | ||
| 55 | jointerms!(result.terms, terms(p1), terms(p2)) | ||
| 56 | result | ||
| 57 | end | ||
| 58 | function MA.mutable_operate_to!(result::Polynomial, ::typeof(*), p::Polynomial, t::AbstractTermLike) | ||
| 59 | if iszero(t) | ||
| 60 | MA.mutable_operate!(zero, result) | ||
| 61 | else | ||
| 62 | resize!(result.terms, nterms(p)) | ||
| 63 | for i in eachindex(p.terms) | ||
| 64 | # TODO could use MA.mul_to! for indices that were presents in `result` before the `resize!`. | ||
| 65 | result.terms[i] = p.terms[i] * t | ||
| 66 | end | ||
| 67 | return result | ||
| 68 | end | ||
| 69 | end | ||
| 70 | function MA.mutable_operate_to!(result::Polynomial, ::typeof(*), t::AbstractTermLike, p::Polynomial) | ||
| 71 | if iszero(t) | ||
| 72 | MA.mutable_operate!(zero, result) | ||
| 73 | else | ||
| 74 | resize!(result.terms, nterms(p)) | ||
| 75 | for i in eachindex(p.terms) | ||
| 76 | # TODO could use MA.mul_to! for indices that were presents in `result` before the `resize!`. | ||
| 77 | result.terms[i] = t * p.terms[i] | ||
| 78 | end | ||
| 79 | return result | ||
| 80 | end | ||
| 81 | end | ||
| 82 | (-)(p1::Polynomial, p2::Polynomial) = Polynomial(jointerms(terms(p1), (-).(terms(p2)))) | ||
| 83 | (-)(p1::Polynomial, p2::Polynomial{<:UniformScaling}) = p1 - MP.mapcoefficientsnz(J -> J.λ, p2) | ||
| 84 | (-)(p1::Polynomial{<:UniformScaling}, p2::Polynomial) = MP.mapcoefficientsnz(J -> J.λ, p1) - p2 | ||
| 85 | (-)(p1::Polynomial{<:UniformScaling}, p2::Polynomial{<:UniformScaling}) = MP.mapcoefficientsnz(J -> J.λ, p1) - p2 | ||
| 86 | |||
| 87 | function MA.mutable_operate!(op::Union{typeof(+), typeof(-)}, p::Polynomial{T}, q::Polynomial) where T | ||
| 88 | get1(i) = p.terms[i] | ||
| 89 | function get2(i) | ||
| 90 | t = q.terms[i] | ||
| 91 | Term(MA.scaling_convert(T, MA.operate(op, t.coefficient)), t.monomial) | ||
| 92 | end | ||
| 93 | set(i, t::Term) = p.terms[i] = t | ||
| 94 | push(t::Term) = push!(p.terms, t) | ||
| 95 | compare_monomials(t::Term, j::Int) = grlex(q.terms[j].monomial, t.monomial) | ||
| 96 | compare_monomials(i::Int, j::Int) = compare_monomials(get1(i), j) | ||
| 97 | combine(i::Int, j::Int) = p.terms[i] = Term(MA.operate!(op, p.terms[i].coefficient, q.terms[j].coefficient), p.terms[i].monomial) | ||
| 98 | combine(t::Term, j::Int) = Term(MA.operate!(op, t.coefficient, q.terms[j].coefficient), t.monomial) | ||
| 99 | resize(n) = resize!(p.terms, n) | ||
| 100 | # We can modify the coefficient since it's the result of `combine`. | ||
| 101 | keep(t::Term) = !MA.iszero!(t.coefficient) | ||
| 102 | keep(i::Int) = !MA.iszero!(p.terms[i].coefficient) | ||
| 103 | MP.polynomial_merge!( | ||
| 104 | nterms(p), nterms(q), get1, get2, set, push, | ||
| 105 | compare_monomials, combine, keep, resize | ||
| 106 | ) | ||
| 107 | return p | ||
| 108 | end | ||
| 109 | |||
| 110 | (==)(::Variable{N}, ::Variable{N}) where {N} = true | ||
| 111 | (==)(::Variable, ::Variable) = false | ||
| 112 | 57 (7 %) |
57 (7 %)
samples spent in ==
1 (2 %) (incl.) when called from uniqterms! line 108 56 (98 %) (incl.) when called from isless line 9
57 (100 %)
samples spent calling
==
(==)(m1::Monomial{V}, m2::Monomial{V}) where {V} = exponents(m1) == exponents(m2)
|
|
| 113 | |||
| 114 | # Multiplication is handled as a special case so that we can write these | ||
| 115 | # definitions without resorting to promotion: | ||
| 116 | MP.multconstant(α, v::Monomial) = Term(α, v) | ||
| 117 | MP.multconstant(α, v::Variable) = Term(α, Monomial(v)) | ||
| 118 | |||
| 119 | (*)(v1::V, v2::V) where {V <: Variable} = Monomial{(V(),), 1}((2,)) | ||
| 120 | (*)(v1::Variable, v2::Variable) = (*)(promote(v1, v2)...) | ||
| 121 | |||
| 122 | function MP.divides(m1::Monomial{V, N}, m2::Monomial{V, N}) where {V, N} | ||
| 123 | reduce((d, exp) -> d && (exp[1] <= exp[2]), zip(m1.exponents, m2.exponents), init=true) | ||
| 124 | end | ||
| 125 | MP.divides(m1::Monomial, m2::Monomial) = divides(promote(m1, m2)...) | ||
| 126 | function MP.mapexponents(op, m1::M, m2::M) where M<:Monomial | ||
| 127 | 1 (0 %) |
1 (100 %)
samples spent calling
map
M(map(op, m1.exponents, m2.exponents))
|
|
| 128 | end | ||
| 129 | MP.mapexponents(op, m1::Monomial, m2::Monomial) = mapexponents(op, promote(m1, m2)...) | ||
| 130 | #function MP.mapexponents_to!(output::M, op, m1::M, m2::M) where M<:Monomial | ||
| 131 | # map!(op, output.exponents, m1.exponents, m2.exponents) | ||
| 132 | # return output | ||
| 133 | #end | ||
| 134 | #function MP.mapexponents!(op, m1::M, m2::M) where M<:Monomial | ||
| 135 | # map!(op, m1.exponents, m1.exponents, m2.exponents) | ||
| 136 | # return m1 | ||
| 137 | #end | ||
| 138 | |||
| 139 | function MA.mutable_operate_to!(output::Polynomial, ::typeof(*), p::Polynomial, q::Polynomial) | ||
| 140 | empty!(output.terms) | ||
| 141 | MP.mul_to_terms!(output.terms, p, q) | ||
| 142 | sort!(output.terms, lt=(>)) | ||
| 143 | MP.uniqterms!(output.terms) | ||
| 144 | return output | ||
| 145 | end | ||
| 146 | function MA.mutable_operate!(::typeof(*), p::Polynomial, q::Polynomial) | ||
| 147 | return MA.mutable_operate_to!(p, *, MA.mutable_copy(p), q) | ||
| 148 | end | ||
| 149 | |||
| 150 | function MA.mutable_operate!(::typeof(zero), p::Polynomial) | ||
| 151 | empty!(p.terms) | ||
| 152 | return p | ||
| 153 | end | ||
| 154 | function MA.mutable_operate!(::typeof(one), p::Polynomial{T}) where T | ||
| 155 | if isempty(p.terms) | ||
| 156 | push!(p.terms, constantterm(one(T), p)) | ||
| 157 | else | ||
| 158 | t = p.terms[1] | ||
| 159 | p.terms[1] = Term(MA.one!(coefficient(t)), constantmonomial(t)) | ||
| 160 | resize!(p.terms, 1) | ||
| 161 | end | ||
| 162 | return p | ||
| 163 | end | ||
| 164 | |||
| 165 | # The exponents are stored in a tuple, this is not mutable. | ||
| 166 | # We could remove these methods since it is the default. | ||
| 167 | MA.mutability(::Type{<:Monomial}) = MA.NotMutable() | ||
| 168 | MA.mutability(::Type{<:Term}) = MA.NotMutable() | ||
| 169 | # The polynomials can be mutated. | ||
| 170 | MA.mutability(::Type{<:Polynomial}) = MA.IsMutable() | ||
| 171 | |||
| 172 | ^(v::V, x::Integer) where {V <: Variable} = Monomial{(V(),), 1}((x,)) | ||
| 173 | |||
| 174 | # dot(v1::AbstractVector{<:TermLike}, v2::AbstractVector) = dot(v1, v2) | ||
| 175 | # dot(v1::AbstractVector, v2::AbstractVector{<:TermLike}) = dot(v1, v2) | ||
| 176 | # dot(v1::AbstractVector{<:TermLike}, v2::AbstractVector{<:TermLike}) = dot(v1, v2) | ||
| 177 | |||
| 178 | # All of these types are immutable, so there's no need to copy anything to get | ||
| 179 | # a shallow copy. | ||
| 180 | Base.copy(x::TermLike) = x | ||
| 181 | |||
| 182 | # Terms are not mutable under the MutableArithmetics API | ||
| 183 | MA.mutable_copy(p::Polynomial) = Polynomial([Term(MA.copy_if_mutable(t.coefficient), t.monomial) for t in terms(p)]) | ||
| 184 | Base.copy(p::Polynomial) = MA.mutable_copy(p) | ||
| 185 | |||
| 186 | adjoint(v::Variable) = v | ||
| 187 | adjoint(m::Monomial) = m | ||
| 188 | adjoint(t::Term) = Term(adjoint(coefficient(t)), monomial(t)) | ||
| 189 | adjoint(x::Polynomial) = Polynomial(adjoint.(terms(x))) | ||
| 190 | |||
| 191 | function MP.mapcoefficientsnz_to!(output::Polynomial, f::Function, p::Polynomial) | ||
| 192 | resize!(output.terms, nterms(p)) | ||
| 193 | for i in eachindex(p.terms) | ||
| 194 | t = p.terms[i] | ||
| 195 | output.terms[i] = Term(f(coefficient(t)), monomial(t)) | ||
| 196 | end | ||
| 197 | return output | ||
| 198 | end | ||
| 199 | function MP.mapcoefficientsnz_to!(output::Polynomial, f::Function, p::AbstractPolynomialLike) | ||
| 200 | return MP.mapcoefficientsnz_to!(output, f, polynomial(p)) | ||
| 201 | end |