diff --git a/Project.toml b/Project.toml index c222b07f..9e6c0e57 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "Polynomials" uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" license = "MIT" author = "JuliaMath" -version = "3.2.3" +version = "3.2.4" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/Polynomials.jl b/src/Polynomials.jl index 5471684c..8285b013 100644 --- a/src/Polynomials.jl +++ b/src/Polynomials.jl @@ -35,4 +35,6 @@ include("rational-functions/plot-recipes.jl") # compat; opt-in with `using Polynomials.PolyCompat` include("polynomials/Poly.jl") +include("precompiles.jl") + end # module diff --git a/src/common.jl b/src/common.jl index d6cd9c39..967b1ab7 100644 --- a/src/common.jl +++ b/src/common.jl @@ -205,6 +205,55 @@ Calculate the pseudo-Vandermonde matrix of the given polynomial type with the gi """ vander(::Type{<:AbstractPolynomial}, x::AbstractVector, deg::Integer) + +""" + critical_points(p::AbstractPolynomial{<:Real}, I=domain(p); endpoints::Bool=true) + +Return the critical points of `p` (real zeros of the derivative) within `I` in sorted order. + +* `p`: a polynomial + +* `I`: a specification of a closed or infinite domain, defaulting to `Polynomials.domain(p)`. When specified, the values of `extrema(I)` are used with closed endpoints when finite. + +* `endpoints::Bool`: if `true`, return the endpoints of `I` along with the critical points + + +Can be used in conjuction with `findmax`, `findmin`, `argmax`, `argmin`, `extrema`, etc. + +## Example +``` +x = variable() +p = x^2 - 2 +cps = Polynomials.critical_points(p) +findmin(p, cps) # (-2.0, 2.0) +argmin(p, cps) # 0.0 +extrema(p, cps) # (-2.0, Inf) +cps = Polynomials.critical_points(p, (0, 2)) +extrema(p, cps) # (-2.0, 2.0) +``` +""" +function critical_points(p::AbstractPolynomial{T}, I = domain(p); + endpoints::Bool=true) where {T <: Real} + + I′ = Interval(I) + l, r = extrema(I′) + + q = Polynomials.ngcd(derivative(p), derivative(p,2)).v + pts = sort(real.(filter(isreal, roots(q)))) + pts = filter(in(I′), pts) + + !endpoints && return pts + + l !== first(pts) && pushfirst!(pts, l) + r != last(pts) && push!(pts, r) + pts +end + + + + + + """ integrate(p::AbstractPolynomial) diff --git a/src/contrib.jl b/src/contrib.jl index 43426a21..42dc501f 100644 --- a/src/contrib.jl +++ b/src/contrib.jl @@ -174,6 +174,8 @@ struct Interval{T, L <: Bound, R <: Bound} end Interval(f, l) = Interval{Closed, Closed}(f, l) end +Interval(I::Interval) = I +Interval(I) = Interval(extrema(I)...) bounds_types(x::Interval{T,L,R}) where {T,L,R} = (L, R) diff --git a/src/precompiles.jl b/src/precompiles.jl new file mode 100644 index 00000000..8efcfadc --- /dev/null +++ b/src/precompiles.jl @@ -0,0 +1,6 @@ +# precompiles + +p = fromroots(Polynomial, [1,1,2]) +Multroot.multroot(p) +gcd(p, derivative(p); method=:numerical) +uvw(p, derivative(p); method=:numerical) diff --git a/test/StandardBasis.jl b/test/StandardBasis.jl index 8d804023..3ec43bc7 100644 --- a/test/StandardBasis.jl +++ b/test/StandardBasis.jl @@ -900,6 +900,24 @@ end end end +@testset "critical points" begin + for P in (Polynomial, ImmutablePolynomial) + p = fromroots(P, [-1,-1, 2]) |> integrate + cps = Polynomials.critical_points(p, (-5,5); endpoints=false) + @test all(cps .≈ [-1, 2]) + cps = Polynomials.critical_points(p, (0,5); endpoints=false) + @test all(cps .≈ [2]) + + cps = Polynomials.critical_points(p) + m, i = findmin(p, cps) + @test m ≈ -6.0 + x = argmin(p, cps) + @test x ≈ 2.0 + mn, mx = extrema(p, cps) + @test mn ≈ -6.0 && isinf(mx) + end +end + @testset "Integrals and Derivatives" begin # Integrals derivatives @testset for P in Ps