Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nonlinear_polynomial #121

Merged
merged 2 commits into from
Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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