Skip to content

Commit a5886d3

Browse files
authored
Merge pull request #72 from JuliaAlgebra/fix-0.7
Towards v0.7 compatibility
2 parents 82cbdcd + b59b2a1 commit a5886d3

16 files changed

+125
-63
lines changed

REQUIRE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
julia 0.6
2+
Compat 0.49

src/MultivariatePolynomials.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,20 @@ module MultivariatePolynomials
66

77
import Base: *, +, -, /, ^, ==,
88
promote_rule, convert, show, isless, size, getindex,
9-
one, zero, transpose, isapprox, @pure, dot, copy
9+
one, zero, isapprox, @pure, copy
10+
using Compat
11+
import Compat.LinearAlgebra: dot, norm
12+
13+
# The ' operator lowers to `transpose()` in v0.6 and to
14+
# `adjoint()` in v0.7+.
15+
# TOOD: remove this switch when dropping v0.6 support
16+
@static if VERSION <= v"0.7.0-DEV.3351"
17+
import Base: transpose
18+
const adjoint_operator = transpose
19+
else
20+
import Compat.LinearAlgebra: adjoint
21+
const adjoint_operator = adjoint
22+
end
1023

1124
export AbstractPolynomialLike, AbstractTermLike, AbstractMonomialLike
1225
"""

src/comparison.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ Base.iszero(t::AbstractPolynomial) = iszero(nterms(t))
77

88
# See https://github.com/blegat/MultivariatePolynomials.jl/issues/22
99
# avoids the call to be transfered to eqconstant
10-
(==)(α::Void, x::APL) = false
11-
(==)(x::APL, α::Void) = false
10+
(==)(α::Nothing, x::APL) = false
11+
(==)(x::APL, α::Nothing) = false
1212
(==)(α::Dict, x::APL) = false
1313
(==)(x::APL, α::Dict) = false
14-
(==)(α::Void, x::RationalPoly) = false
15-
(==)(x::RationalPoly, α::Void) = false
14+
(==)(α::Nothing, x::RationalPoly) = false
15+
(==)(x::RationalPoly, α::Nothing) = false
1616
(==)(α::Dict, x::RationalPoly) = false
1717
(==)(x::RationalPoly, α::Dict) = false
1818

@@ -100,7 +100,7 @@ end
100100

101101
# α could be a JuMP affine expression
102102
isapproxzero(α; ztol::Real=0.) = false
103-
function isapproxzero::Number; ztol::Real=Base.rtoldefault(α, α))
103+
function isapproxzero::Number; ztol::Real=Base.rtoldefault(α, α, 0))
104104
abs(α) <= ztol
105105
end
106106

src/conversion.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export variable
22

3-
function convertconstant end
3+
convertconstant(::Type{P}, α) where P<:APL = P(α)
44
convert(::Type{P}, α) where P<:APL = convertconstant(P, α)
5-
convert(::Type{P}, p::APL) where P<:AbstractPolynomial = convert(P, polynomial(p))
5+
convert(::Type{P}, p::APL) where P<:AbstractPolynomial = P(polynomial(p))
66

77
Base.convert(::Type{Any}, p::APL) = p
88
# Conversion polynomial -> scalar
@@ -11,12 +11,16 @@ function Base.convert(::Type{S}, p::APL) where {S}
1111
for t in terms(p)
1212
if !isconstant(t)
1313
# The polynomial is not constant
14-
throw(InexactError())
14+
throw(InexactError(:convert, S, p))
1515
end
1616
s += S(coefficient(t))
1717
end
1818
s
1919
end
20+
21+
# Fix ambiguity caused by above conversions
22+
Base.convert(::Type{P}, p::APL) where P<:APL = P(p)
23+
2024
Base.convert(::Type{PT}, p::PT) where {PT<:APL} = p
2125
function Base.convert(::Type{MT}, t::AbstractTerm) where {MT<:AbstractMonomial}
2226
if isone(coefficient(t))

src/differentiation.jl

Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@
22
export differentiate
33

44
"""
5-
differentiate(p::AbstractPolynomialLike, v::AbstractVariable, deg::Int=1)
5+
differentiate(p::AbstractPolynomialLike, v::AbstractVariable, deg::Union{Int, Val}=1)
66
77
Differentiate `deg` times the polynomial `p` by the variable `v`.
88
9-
differentiate(p::AbstractPolynomialLike, vs, deg::Int=1)
109
11-
Differentiate `deg` times the polynomial `p` by the variables of the vector or tuple of variable `vs` and return an array of dimension `deg`.
10+
differentiate(p::AbstractPolynomialLike, vs, deg::Union{Int, Val}=1)
1211
13-
differentiate(p::AbstractArray{<:AbstractPolynomialLike, N}, vs, deg::Int=1) where N
12+
Differentiate `deg` times the polynomial `p` by the variables of the vector or
13+
tuple of variable `vs` and return an array of dimension `deg`. It is recommended
14+
to pass `deg` as a `Val` instance when the degree is known at compile time, e.g.
15+
`differentiate(p, v, Val{2}())` instead of `differentiate(p, x, 2)`, as this
16+
will help the compiler infer the return type.
17+
18+
differentiate(p::AbstractArray{<:AbstractPolynomialLike, N}, vs, deg::Union{Int, Val}=1) where N
1419
1520
Differentiate the polynomials in `p` by the variables of the vector or tuple of variable `vs` and return an array of dimension `N+deg`.
1621
@@ -19,63 +24,84 @@ Differentiate the polynomials in `p` by the variables of the vector or tuple of
1924
```julia
2025
p = 3x^2*y + x + 2y + 1
2126
differentiate(p, x) # should return 6xy + 1
27+
differentiate(p, x, Val{1}()) # equivalent to the above
2228
differentiate(p, (x, y)) # should return [6xy+1, 3x^2+1]
2329
```
2430
"""
2531
function differentiate end
2632

2733
# Fallback for everything else
28-
_diff_promote_op(::Type{T}, ::Type{<:AbstractVariable}) where T = T
2934
differentiate::T, v::AbstractVariable) where T = zero(T)
30-
31-
_diff_promote_op(::Type{<:AbstractVariable}, ::Type{<:AbstractVariable}) = Int
3235
differentiate(v1::AbstractVariable, v2::AbstractVariable) = v1 == v2 ? 1 : 0
33-
34-
_diff_promote_op(::Type{TT}, ::Type{<:AbstractVariable}) where {T, TT<:AbstractTermLike{T}} = changecoefficienttype(TT, Base.promote_op(*, T, Int))
3536
differentiate(t::AbstractTermLike, v::AbstractVariable) = coefficient(t) * differentiate(monomial(t), v)
36-
37-
_diff_promote_op(::Type{PT}, ::Type{<:AbstractVariable}) where {T, PT<:APL{T}} = polynomialtype(PT, Base.promote_op(*, T, Int))
3837
# The polynomial function will take care of removing the zeros
3938
differentiate(p::APL, v::AbstractVariable) = polynomial(differentiate.(terms(p), v), SortedState())
40-
4139
differentiate(p::RationalPoly, v::AbstractVariable) = (differentiate(p.num, v) * p.den - p.num * differentiate(p.den, v)) / p.den^2
4240

4341
const ARPL = Union{APL, RationalPoly}
4442

45-
_vec_diff_promote_op(::Type{PT}, ::AbstractVector{VT}) where {PT, VT} = _diff_promote_op(PT, VT)
46-
_vec_diff_promote_op(::Type{PT}, ::NTuple{N, VT}) where {PT, N, VT} = _diff_promote_op(PT, VT)
47-
_vec_diff_promote_op(::Type{PT}, ::VT, xs...) where {PT, VT} = _diff_promote_op(PT, VT)
48-
_vec_diff_promote_op(::Type{PT}, xs::Tuple) where PT = _vec_diff_promote_op(PT, xs...)
49-
50-
# even if I annotate with ::Array{_diff_promote_op(T, PolyVar{C}), N+1}, it cannot detect the type since it seems to be unable to determine the dimension N+1 :(
51-
function differentiate(ps::AbstractArray{PT, N}, xs::Union{AbstractArray, Tuple}) where {N, PT<:ARPL}
52-
qs = Array{_vec_diff_promote_op(PT, xs), N+1}(length(xs), size(ps)...)
53-
for (i, x) in enumerate(xs)
54-
for j in linearindices(ps)
55-
J = ind2sub(ps, j)
56-
qs[i, J...] = differentiate(ps[J...], x)
57-
end
58-
end
59-
qs
43+
function differentiate(ps::AbstractArray{PT}, xs::AbstractArray) where {PT <: ARPL}
44+
differentiate.(reshape(ps, (1, size(ps)...)), reshape(xs, :))
45+
end
46+
47+
function differentiate(ps::AbstractArray{PT}, xs::Tuple) where {PT <: ARPL}
48+
differentiate.(reshape(ps, (1, size(ps)...)), xs)
6049
end
6150

51+
52+
# TODO: this signature is probably too wide and creates the potential
53+
# for stack overflows
6254
differentiate(p::ARPL, xs) = [differentiate(p, x) for x in xs]
6355

6456
# differentiate(p, [x, y]) with TypedPolynomials promote x to a Monomial
6557
differentiate(p::ARPL, m::AbstractMonomial) = differentiate(p, variable(m))
6658

67-
# In Julia v0.5, Base.promote_op returns Any for PolyVar, Monomial and MatPolynomial
68-
# Even on Julia v0.6 and Polynomial, Base.promote_op returns Any...
69-
_diff_promote_op(::Type{PT}, ::Type{VT}) where {PT, VT} = Base.promote_op(differentiate, PT, VT)
70-
_diff_promote_op(::Type{MT}, ::Type{<:AbstractVariable}) where {MT<:AbstractMonomialLike} = termtype(MT, Int)
71-
72-
function differentiate(p, x, deg::Int)
59+
# The `R` argument indicates a desired result type. We use this in order
60+
# to attempt to preserve type-stability even though the value of `deg` cannot
61+
# be known at compile time. For scalar `p` and `x`, we set R to be the type
62+
# of differentiate(p, x) to give a stable result type regardless of `deg`. For
63+
# vectors p and/or x this is impossible (since differentiate may return an array),
64+
# so we just set `R` to `Any`
65+
function (_differentiate_recursive(p, x, deg::Int, ::Type{R})::R) where {R}
7366
if deg < 0
7467
throw(DomainError())
7568
elseif deg == 0
76-
# Need the conversion with promote_op to be type stable for PolyVar, Monomial and MatPolynomial
77-
return convert(_diff_promote_op(typeof(p), typeof(x)), p)
69+
return p
7870
else
7971
return differentiate(differentiate(p, x), x, deg-1)
8072
end
8173
end
74+
75+
differentiate(p, x, deg::Int) = _differentiate_recursive(p, x, deg, Base.promote_op(differentiate, typeof(p), typeof(x)))
76+
differentiate(p::AbstractArray, x, deg::Int) = _differentiate_recursive(p, x, deg, Any)
77+
differentiate(p, x::Union{AbstractArray, Tuple}, deg::Int) = _differentiate_recursive(p, x, deg, Any)
78+
differentiate(p::AbstractArray, x::Union{AbstractArray, Tuple}, deg::Int) = _differentiate_recursive(p, x, deg, Any)
79+
80+
81+
# This is alternative, Val-based interface for nested differentiation.
82+
# It has the advantage of not requiring an conversion or calls to
83+
# Base.promote_op, while maintaining type stability for any argument
84+
# type.
85+
differentiate(p, x, ::Val{0}) = p
86+
differentiate(p, x, ::Val{1}) = differentiate(p, x)
87+
88+
@static if VERSION < v"v0.7.0-"
89+
# Marking this @pure helps julia v0.6 figure this out
90+
Base.@pure _reduce_degree(::Val{N}) where {N} = Val{N - 1}()
91+
function differentiate(p, x, deg::Val{N}) where N
92+
if N < 0
93+
throw(DomainError(deg))
94+
else
95+
differentiate(differentiate(p, x), x, _reduce_degree(deg))
96+
end
97+
end
98+
else
99+
# In Julia v0.7 and above, we can remove the _reduce_degree trick
100+
function differentiate(p, x, deg::Val{N}) where N
101+
if N < 0
102+
throw(DomainError(deg))
103+
else
104+
differentiate(differentiate(p, x), x, Val{N - 1}())
105+
end
106+
end
107+
end

src/division.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function Base.divrem(f::APL{T}, g::AbstractVector{<:APL{S}}; kwargs...) where {T
6767
lt = leadingterm.(g)
6868
rg = removeleadingterm.(g)
6969
lm = monomial.(lt)
70-
useful = IntSet(eachindex(g))
70+
useful = BitSet(eachindex(g))
7171
while !iszero(rf)
7272
ltf = leadingterm(rf)
7373
if isapproxzero(ltf; kwargs...)

src/monomial.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ degree(v::AbstractVariable, var::AbstractVariable) = (v == var ? 1 : 0)
7171
#_deg(v::AbstractVariable) = 0
7272
#_deg(v::AbstractVariable, power, powers...) = v == power[1] ? power[2] : _deg(v, powers...)
7373
#degree(m::AbstractMonomial, v::AbstractVariable) = _deg(v, powers(t)...)
74+
7475
function degree(m::AbstractMonomial, v::AbstractVariable)
75-
i = findfirst(variables(m), v)
76-
if i == nothing || iszero(i)
76+
i = findfirst(equalto(v), variables(m))
77+
if i === nothing || iszero(i)
7778
0
7879
else
7980
exponents(m)[i]

src/monovec.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Calling `monovec` on ``[xy, x, xy, x^2y, x]`` should return ``[x^2y, xy, x]``.
2020
"""
2121
function monovec(X::AbstractVector{MT}) where {MT<:AbstractMonomial}
2222
Y = sort(X, rev=true)
23-
dups = find(i -> Y[i] == Y[i-1], 2:length(Y))
23+
dups = findall(i -> Y[i] == Y[i-1], 2:length(Y))
2424
deleteat!(Y, dups)
2525
Y
2626
end
@@ -54,7 +54,7 @@ Calling `sortmonovec` on ``[xy, x, xy, x^2y, x]`` should return ``([4, 1, 2], [x
5454
"""
5555
function sortmonovec(X::AbstractVector{MT}) where {MT<:AbstractMonomial}
5656
σ = sortperm(X, rev=true)
57-
dups = find(i -> X[σ[i]] == X[σ[i-1]], 2:length(σ))
57+
dups = findall(i -> X[σ[i]] == X[σ[i-1]], 2:length(σ))
5858
deleteat!(σ, dups)
5959
σ, X[σ]
6060
end

src/operators.jl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,14 @@ for op in [:+, :-]
9999
end
100100
end
101101

102-
Base.transpose(v::AbstractVariable) = v
103-
Base.transpose(m::AbstractMonomial) = m
104-
Base.transpose(t::T) where {T <: AbstractTerm} = transpose(coefficient(t)) * monomial(t)
105-
Base.transpose(p::AbstractPolynomialLike) = polynomial(map(transpose, terms(p)))
102+
adjoint_operator(v::AbstractVariable) = v
103+
adjoint_operator(m::AbstractMonomial) = m
104+
adjoint_operator(t::T) where {T <: AbstractTerm} = adjoint_operator(coefficient(t)) * monomial(t)
105+
adjoint_operator(p::AbstractPolynomialLike) = polynomial(map(adjoint_operator, terms(p)))
106106

107-
Base.dot(p1::AbstractPolynomialLike, p2::AbstractPolynomialLike) = p1' * p2
108-
Base.dot(x, p::AbstractPolynomialLike) = x' * p
109-
Base.dot(p::AbstractPolynomialLike, x) = p' * x
107+
dot(p1::AbstractPolynomialLike, p2::AbstractPolynomialLike) = p1' * p2
108+
dot(x, p::AbstractPolynomialLike) = x' * p
109+
dot(p::AbstractPolynomialLike, x) = p' * x
110110

111111
# Amazingly, this works! Thanks, StaticArrays.jl!
112112
"""
@@ -115,3 +115,6 @@ The element type of the vector will be Monomial{vars, length(vars)}.
115115
"""
116116
Base.vec(vars::Tuple{Vararg{AbstractVariable}}) = [vars...]
117117
# vec(vars::Tuple{Vararg{<:TypedVariable}}) = SVector(vars)
118+
119+
# https://github.com/JuliaLang/julia/pull/23332
120+
^(x::AbstractPolynomialLike, p::Integer) = Base.power_by_squaring(x, p)

src/polynomial.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export mindegree, maxdegree, extdegree
44
export leadingterm, leadingcoefficient, leadingmonomial
55
export removeleadingterm, removemonomials, monic
66

7-
Base.norm(p::AbstractPolynomialLike, r::Int=2) = norm(coefficients(p), r)
7+
norm(p::AbstractPolynomialLike, r::Int=2) = norm(coefficients(p), r)
88

99
changecoefficienttype(::Type{TT}, ::Type{T}) where {TT<:AbstractTermLike, T} = termtype(TT, T)
1010
changecoefficienttype(::Type{PT}, ::Type{T}) where {PT<:AbstractPolynomial, T} = polynomialtype(PT, T)

0 commit comments

Comments
 (0)