Skip to content

Commit

Permalink
Add nonlinear_polynomial (#121)
Browse files Browse the repository at this point in the history
* Add nonlinear_polynomial with tests

Closes #106

* Use linear_polynomial and nonlinear_polynomial
  • Loading branch information
lbenet authored Jul 1, 2021
1 parent 7441eb2 commit 0f43d54
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 91 deletions.
3 changes: 2 additions & 1 deletion src/TaylorModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import Base: setindex!, getindex, copy, firstindex, lastindex,
using TaylorSeries: derivative, ∇

import TaylorSeries: integrate, get_order, evaluate, pretty_print,
constant_term, linear_polynomial, fixorder, get_numvars
constant_term, linear_polynomial, nonlinear_polynomial,
fixorder, get_numvars

import IntervalArithmetic: showfull

Expand Down
9 changes: 5 additions & 4 deletions src/auxiliary.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ for TM in (:TaylorModel1, :RTaylorModel1, :TaylorModelN)
@inline firstindex(a::$TM) = 0
@inline lastindex(a::$TM) = get_order(a)

getindex(a::$TM, n::Integer) = a.pol[n]
getindex(a::$TM, u::UnitRange) = a.pol[u]
getindex(a::$TM, c::Colon) = a.pol[c]
# getindex(a::$TM, u::StepRange{Int,Int}) = a.pol[u[:]]
getindex(a::$TM, n::Integer) = getindex(polynomial(a), n)
getindex(a::$TM, u::UnitRange) = getindex(polynomial(a), u)
getindex(a::$TM, c::Colon) = getindex(polynomial(a), c)
# getindex(a::$TM, u::StepRange{Int,Int}) = getindex(polynomial(a), u)

constant_term(a::$TM) = constant_term(polynomial(a))
linear_polynomial(a::$TM) = linear_polynomial(polynomial(a))
nonlinear_polynomial(a::$TM) = nonlinear_polynomial(polynomial(a))

# norm
norm(x::$TM, p::Real=2) = norm(polynomial(x), p)
Expand Down
189 changes: 103 additions & 86 deletions src/bounds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ function bound_remainder(::Type{TaylorModel1}, f::Function, polf::Taylor1, polfI
fTIend = polfI[_order]
if (sup(fTIend) < 0 || inf(fTIend) > 0)
# Absolute remainder is monotonic
a = interval(I.lo)
b = interval(I.hi)
a = Interval(inf(I))
b = Interval(sup(I))
Δlo = f(a) - polf(a-x0)
# Δlo = f(a) - bound_taylor1(polf, a-x0)
Δhi = f(b) - polf(b-x0)
# Δhi = f(b) - bound_taylor1(polf, b-x0)
Δx0 = f(x0) - polf[0]
Δ = hull(hull(Δlo, Δx0), Δhi)
Δ = hull(Δlo, Δx0, Δhi)
else
# Lagrange bound
Δ = fTIend * (I-x0)^_order
Expand All @@ -41,16 +41,15 @@ function bound_remainder(::Type{TaylorModel1}, f::Function, polf::Taylor1{Taylor
fTIend = polfI[_order]
if (sup(fTIend) < 0 || inf(fTIend) > 0)
# Absolute remainder is monotonic
a = interval(I.lo)
b = interval(I.hi)
N = get_numvars()
symIbox = IntervalBox(-1 .. 1, Val(N))
a = Interval(inf(I))
b = Interval(sup(I))
symIbox = IntervalBox(-1 .. 1, get_numvars())
Δlo = (f(a) - polf(a-x0))(symIbox)
# Δlo = f(a) - bound_taylor1(polf, a-x0)
Δhi = (f(b) - polf(b-x0))(symIbox)
# Δhi = f(b) - bound_taylor1(polf, b-x0)
Δx0 = (f(x0) - polf[0])(symIbox)
Δ = hull(hull(Δlo, Δx0), Δhi)
Δ = hull(Δlo, Δx0, Δhi)
else
# Lagrange bound
Δ = fTIend * (I-x0)^_order
Expand All @@ -76,8 +75,8 @@ function bound_remainder(::Type{RTaylorModel1}, f::Function, polf::Taylor1, polf

_order = get_order(polf) + 1
fTIend = polfI[_order+1]
a = interval(I.lo)
b = interval(I.hi)
a = Interval(inf(I))
b = Interval(sup(I))
if (sup(fTIend) < 0 || inf(fTIend) > 0) && isempty(a x0) && isempty(b x0)
# Error is monotonic
denom_lo = (a-x0)^_order
Expand Down Expand Up @@ -123,8 +122,8 @@ function bound_taylor1(fT::Taylor1, I::Interval)
# Bound the range of fT using the roots and end points
num_roots = length(rootsder)
num_roots == 0 && return fT(I)
rangepoly = hull( fT(interval(I.lo)), fT(interval(I.hi)) )
for ind in 1:num_roots
rangepoly = hull( fT(Interval(inf(I))), fT(Interval(sup(I))) )
@inbounds for ind in 1:num_roots
rangepoly = hull(rangepoly, fT(rootsder[ind].interval))
end

Expand All @@ -142,20 +141,24 @@ a definite sign.
"""
function bound_taylor1(fT::Taylor1{T}, fTd::Taylor1{T}, I::Interval{T}) where {T}
#
I_lo = inf(I)
I_hi = sup(I)
if inf(fTd(I)) 0
return Interval(fT(I.lo), fT(I.hi))
return Interval(fT(I_lo), fT(I_hi))
elseif sup(fTd(I)) 0
return Interval(fT(I.hi), fT(I.lo))
return Interval(fT(I_hi), fT(I_lo))
end
return fT(I)
end
function bound_taylor1(fT::Taylor1{Interval{T}}, fTd::Taylor1{Interval{T}},
I::Interval{S}) where {T,S}
#
I_lo = inf(I)
I_hi = sup(I)
if inf(fTd(I)) 0
return hull(fT(I.lo), fT(I.hi))
return hull(fT(I_lo), fT(I_hi))
elseif sup(fTd(I)) 0
return hull(fT(I.hi), fT(I.lo))
return hull(fT(I_hi), fT(I_lo))
end
return fT(I)
end
Expand All @@ -180,42 +183,47 @@ The returned bound corresponds to the improved polynomial bound with the remaind
of the `TaylorModel1` included.
"""
function linear_dominated_bounder(fT::TaylorModel1{T, S}; ϵ=1e-3, max_iter=5) where {T, S}
d = 1.
Dn = fT.dom
Dm = fT.x0
Pm = Taylor1(copy(fT.pol.coeffs))
bound = interval(0.)
d = one(T)
dom = domain(fT)
x0 = expansion_point(fT)
pol = polynomial(fT)
Pm = deepcopy(pol)
bound = zero_interval(S)
hi = sup(pol(dom - x0))

n_iter = 0
while d > ϵ && n_iter < max_iter
x0 = mid(Dn - Dm)
c = mid(Dn)
x0 = mid(dom - x0)
c = mid(dom)
update!(Pm, x0)
linear = Taylor1(Pm.coeffs[1:2], Pm.order)
non_linear = Pm - linear
non_linear = nonlinear_polynomial(Pm)
linear = Pm - non_linear
if T <: Interval
Li = mid(linear[1])
else
Li = linear[1]
end
I1 = linear(Dn - c)
Ih = non_linear(Dn - c)
bound = I1.lo + Ih
I1 = linear(dom - c)
Ih = non_linear(dom - c)
bound = inf(I1) + Ih
d = diam(bound)
n_iter += 1
dom_lo = inf(dom)
dom_hi = sup(dom)
if Li == 0
break
elseif Li > 0
new_hi = min(Dn.lo + (d / abs(Li)), Dn.hi)
Dm = Dn
Dn = interval(Dn.lo, new_hi)
new_hi = min(dom_lo + (d / abs(Li)), dom_hi)
x0 = dom
dom = Interval(dom_lo, new_hi)
else
new_lo = max(Dn.hi - (d / abs(Li)), Dn.lo)
Dm = Dn
Dn = interval(new_lo, Dn.hi)
new_lo = max(dom_hi - (d / abs(Li)), dom_lo)
x0 = dom
dom = Interval(new_lo, dom_hi)
end
end
hi = fT.pol(fT.dom - fT.x0).hi
return interval(bound.lo, hi) + fT.rem

return Interval(inf(bound), hi) + remainder(fT)
end

"""
Expand All @@ -227,52 +235,57 @@ the bound of `fT` gets tighter than `ϵ` or the number of steps reachs `max_iter
The returned bound corresponds to the improved polynomial bound with the remainder
of the `TaylorModelN` included.
"""
function linear_dominated_bounder(fT::TaylorModelN{N, T, S}; ϵ=1e-5, max_iter=5) where {N, T, S}
d = 1.
Dn = fT.dom
Dm = fT.x0
Pm = TaylorN(deepcopy(fT.pol.coeffs))
bound = interval(0.)
function linear_dominated_bounder(fT::TaylorModelN{N,T,S}; ϵ=1e-5, max_iter=5) where {N, T, S}
d = one(T)
dom = domain(fT)
x0 = expansion_point(fT)
pol = polynomial(fT)
Pm = deepcopy(pol)
bound = zero_interval(S)
pol_hi = sup(pol(dom - x0))

n_iter = 0
x0 = Array{S}(undef, N)
x00 = Array{S}(undef, N)
new_boxes = fill(bound, N)
linear_coeffs = Array{Float64}(undef, N)
while d > ϵ && n_iter < max_iter
x0 .= mid(Dn - Dm)
c = mid(Dn)
update!(Pm, x0)
x00 .= mid(dom - x0)
c = mid(dom)
update!(Pm, x00)
linear_part = Pm[1]
if T <: Interval
linear_coeffs .= mid.(linear_part.coeffs)
@. linear_coeffs = mid(linear_part.coeffs)
else
linear_coeffs .= linear_part.coeffs
@. linear_coeffs = linear_part.coeffs
end
linear = TaylorN(deepcopy(Pm.coeffs[1:2]), Pm.order)
non_linear = Pm - linear
centered_domain = Dn .- c
non_linear = nonlinear_polynomial(Pm)
linear = Pm - non_linear
centered_domain = dom .- c
I1 = linear(centered_domain)
Ih = non_linear(centered_domain)
bound = I1.lo + Ih
bound = inf(I1) + Ih
d = diam(bound)
n_iter += 1
new_boxes = Interval[]
for (idx, box) in enumerate(Dn)
for (idx, box) in enumerate(dom)
Li = linear_coeffs[idx]
box_lo = inf(box)
box_hi = sup(box)
if Li == 0
Dni = box
domi = box
elseif Li < 0
lo = max(box.hi - (d / abs(Li)), box.lo)
Dni = interval(lo, box.hi)
lo = max(box_hi - (d / abs(Li)), box_lo)
domi = Interval(lo, box_hi)
else
hi = min(box.lo + (d / abs(Li)), box.hi)
Dni = interval(box.lo, hi)
hi = min(box_lo + (d / abs(Li)), box_hi)
domi = Interval(box_lo, hi)
end
push!(new_boxes, Dni)
new_boxes[idx] = domi
end
Dm = Dn
Dn = IntervalBox(new_boxes...)
x0 = dom
dom = IntervalBox(new_boxes...)
end
hi = fT.pol(fT.dom - fT.x0).hi
return interval(bound.lo, hi) + fT.rem

return Interval(inf(bound), pol_hi) + remainder(fT)
end

"""
Expand All @@ -292,20 +305,21 @@ For this algorithm the linear part is bounded by solving a simple
set of linear equations (compared to the iterative procedure by Makino & Berz).
"""
function quadratic_fast_bounder(fT::TaylorModel1)
P = fT.pol
bound_tm = fT(fT.dom - fT.x0)
if signbit(P[2])
return bound_tm
else
x0 = -P[1] / (2 * P[2])
x = Taylor1(fT.pol.order)
Qx0 = (x - x0) * P[2] * (x - x0)
bound_qfb = (P - Qx0)(fT.dom - fT.x0)
hi = P(fT.dom - fT.x0).hi
bound_qfb = interval(bound_qfb.lo, hi) + fT.rem
bound = bound_qfb bound_tm
return bound
end
P = polynomial(fT)
dom = domain(fT)
x00 = expansion_point(fT)
bound_tm = fT(dom - x00)
signbit(P[2]) && return bound_tm

cent_dom = dom - x00
x0 = -P[1] / (2 * P[2])
x = Taylor1(P.order)
Qx0 = (x - x0) * P[2] * (x - x0)
bound_qfb = (P - Qx0)(cent_dom)
hi = sup(P(cent_dom))
bound_qfb = Interval(inf(bound_qfb), hi) + remainder(fT)

return bound_qfb bound_tm
end

"""
Expand All @@ -325,20 +339,23 @@ For this algorithm the linear part is bounded by solving a simple
set of linear equations (compared to the iterative procedure by Makino & Berz).
"""
function quadratic_fast_bounder(fT::TaylorModelN)
P = fT.pol
@assert get_numvars() == get_numvars(fT)
P = polynomial(fT)
dom = domain(fT)
x0 = expansion_point(fT)
H = Matrix(TaylorSeries.hessian(P))
bound_tm = fT(fT.dom - fT.x0)
bound_tm = fT(dom - x0)
if isposdef(H)
P1 = -P[1].coeffs
xn = H \ P1
x = set_variables("x", numvars=length(xn))
x = get_variables()#set_variables("x", numvars=length(xn))
Qxn = 0.5 * (x - xn)' * H * (x - xn)
bound_qfb = (P - Qxn)(fT.dom - fT.x0)
hi = P(fT.dom - fT.x0).hi
bound_qfb = interval(bound_qfb.lo, hi) + fT.rem
bound_qfb = (P - Qxn)(dom - x0)
hi = sup(P(dom - x0))
bound_qfb = interval(inf(bound_qfb), hi) + remainder(fT)
bound = bound_qfb bound_tm
return bound
else
return bound_tm
end

return bound_tm
end
9 changes: 9 additions & 0 deletions test/TM1.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ end
@test expansion_point(tv) == x0
@test constant_term(tv) == interval(0.0)
@test linear_polynomial(tv) == Taylor1(Interval{Float64},5)
@test nonlinear_polynomial(tv) == zero(Taylor1(Interval{Float64},5))

# Tests related to fixorder
a = TaylorModel1(Taylor1([1.0, 1]), 0..1, 0..0, -1 .. 1)
Expand Down Expand Up @@ -99,10 +100,14 @@ end
b = a * tv
@test b == TaylorModel1(a.pol*tv.pol, a.rem*tv.pol(ii1-x1), x1, ii1)
@test remainder(b/tv) Interval(-0.78125, 0.84375)
@test constant_term(b) == 1..1
@test linear_polynomial(b) == 2*x1*Taylor1(5)
@test nonlinear_polynomial(b) == x1*Taylor1(5)^2
b = a * a.pol[0]
@test b == a
@test constant_term(a) == x1
@test linear_polynomial(a) == Taylor1(5)
@test nonlinear_polynomial(a) == Taylor1(0..0, 5)

a = TaylorModel1(x0, 5, x0, ii0)
@test a^0 == TaylorModel1(x0^0, 5, x0, ii0)
Expand Down Expand Up @@ -579,6 +584,7 @@ end
@test expansion_point(tv) == x0
@test constant_term(tv) == interval(0.0)
@test linear_polynomial(tv) == Taylor1(Interval{Float64},5)
@test nonlinear_polynomial(tv) == zero(Taylor1(Interval{Float64},5))

# Tests related to fixorder
a = RTaylorModel1(Taylor1([1.0, 1]), 0..1, 0..0, -1 .. 1)
Expand Down Expand Up @@ -607,10 +613,13 @@ end
b = a * tv
@test b == RTaylorModel1(a.pol*tv.pol, a.rem*tv.pol(ii1-x1), x1, ii1)
@test remainder(b/tv) Interval(-2.75, 4.75)
@test linear_polynomial(b) == 2*x1*Taylor1(5)
@test nonlinear_polynomial(b) == x1*Taylor1(5)^2
b = a * a.pol[0]
@test b == a
@test constant_term(a) == x1
@test linear_polynomial(a) == Taylor1(5)
@test nonlinear_polynomial(a) == Taylor1(0..0, 5)

a = RTaylorModel1(x0, 5, x0, ii0)
@test a^0 == RTaylorModel1(x0^0, 5, x0, ii0)
Expand Down
2 changes: 2 additions & 0 deletions test/TMN.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ set_variables(Interval{Float64}, [:x, :y], order=_order_max)
@test linear_polynomial(xm) == xT
@test linear_polynomial(ym) == yT
@test linear_polynomial(xm^2) == zero(xT)
@test nonlinear_polynomial(xm) == zero(xT)
@test nonlinear_polynomial(xm^2) == xT^2
end

@testset "Arithmetic operations" begin
Expand Down

2 comments on commit 0f43d54

@lbenet
Copy link
Member Author

@lbenet lbenet commented on 0f43d54 Jul 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error while trying to register: "Tag with name v0.4.0 already exists and points to a different commit"

Please sign in to comment.