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

Modify signature of evaluate for TaylorN's #247

Merged
merged 7 commits into from
Jan 12, 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
29 changes: 29 additions & 0 deletions docs/src/userguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,35 @@ exy([.1,.02]) == exp(0.12)
exy(:x, 0.0)
```

Internally, `evaluate` for `TaylorN` considers separately
the contributions of all `HomogeneousPolynomial`s by `order`,
which are finally added up *after* sorting them in place (which is the default)
in increasing order by `abs2`. This is done in order to
use as many significant figures as possible of all terms
in the final sum, which then should yield a more
accurate result. This default can be changed to a non-sorting
sum thought, which may be more performant or useful for
certain subtypes of `Number` which, for instance, do not have `isless`
defined. See
[this issue](https://github.com/JuliaDiff/TaylorSeries.jl/issues/242)
for a motivating example. This can be done using the keyword
`sorting` in `evaluate`, which expects a `Bool`, or using a
that boolean as the *first* argument in the function-like evaluation.

```@repl userguide
exy([.1,.02]) # default is `sorting=true`
evaluate(exy, [.1,.02]; sorting=false)
exy(false, [.1,.02])
```

In the examples shown above, the first entry corresponds to the
default case (`sorting=true`), which yields the same result as
`exp(0.12)`, and the remaining two illustrate
turning off sorting the terms. Note that the results are not
identical, since [floating point addition is not
associative](https://en.wikipedia.org/wiki/Associative_property#Nonassociativity_of_floating_point_calculation),
which may introduce rounding errors.

The functions `taylor_expand` and `update!` work as well for `TaylorN`.

```@repl userguide
Expand Down
59 changes: 32 additions & 27 deletions src/evaluate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,9 @@ representing the Taylor expansion for the dependent variables
of an ODE at *time* `δt`. It updates the vector `x0` with the
computed values.
"""
function evaluate!(x::AbstractArray{Taylor1{T}}, δt::T,
x0::AbstractArray{T}) where {T<:Number}

# @assert length(x) == length(x0)
@inbounds for i in eachindex(x, x0)
x0[i] = evaluate( x[i], δt )
end
nothing
end
function evaluate!(x::AbstractArray{Taylor1{T}}, δt::S,
x0::AbstractArray{T}) where {T<:Number, S<:Number}

# @assert length(x) == length(x0)
@inbounds for i in eachindex(x, x0)
x0[i] = evaluate( x[i], δt )
end
Expand Down Expand Up @@ -110,7 +100,6 @@ evaluate(p::Taylor1{T}, x::Array{S}) where {T<:Number, S<:Number} =

#function-like behavior for Taylor1
(p::Taylor1)(x) = evaluate(p, x)

(p::Taylor1)() = evaluate(p)

#function-like behavior for Vector{Taylor1}
Expand Down Expand Up @@ -146,11 +135,10 @@ function evaluate!(x::AbstractArray{TaylorN{T}}, δx::Array{Taylor1{T},1},
end

function evaluate!(x::AbstractArray{TaylorN{T}}, δx::Array{TaylorN{T},1},
x0::AbstractArray{TaylorN{T}}) where {T<:NumberNotSeriesN}
x0::AbstractArray{TaylorN{T}}; sorting::Bool=true) where {T<:NumberNotSeriesN}

# @assert length(x) == length(x0)
@inbounds for i in eachindex(x, x0)
x0[i] = evaluate( x[i], δx )
x0[i] = _evaluate( x[i], δx, Val(sorting) )
lbenet marked this conversation as resolved.
Show resolved Hide resolved
end
nothing
end
Expand Down Expand Up @@ -202,7 +190,7 @@ evaluate(a::HomogeneousPolynomial{T}, vals::Array{S,1} ) where

evaluate(a::HomogeneousPolynomial, v, vals...) = evaluate(a, (v, vals...,))

evaluate(a::HomogeneousPolynomial, v) = evaluate(a, v...)
evaluate(a::HomogeneousPolynomial, v) = evaluate(a, [v...])
lbenet marked this conversation as resolved.
Show resolved Hide resolved

function evaluate(a::HomogeneousPolynomial)
a.order == 0 && return a[1]
Expand All @@ -217,31 +205,46 @@ end
(p::HomogeneousPolynomial)() = evaluate(p)

"""
evaluate(a, [vals])
evaluate(a, [vals]; sorting::Bool=true)

Evaluate the `TaylorN` polynomial `a` at `vals`.
If `vals` is ommitted, it's evaluated at zero.
Note that the syntax `a(vals)` is equivalent to `evaluate(a, vals)`; and `a()`
is equivalent to `evaluate(a)`.
If `vals` is ommitted, it's evaluated at zero. The
keyword parameter `sorting` can be used to avoid
sorting (in increasing order by `abs2`) the
terms that are added.

Note that the syntax `a(vals)` is equivalent to
`evaluate(a, vals)`; and `a()` is equivalent to
`evaluate(a)`. No extension exists that incorporates
`sorting`.
"""
function evaluate(a::TaylorN{T}, vals::NTuple{N,S}) where
{T<:Number,S<:NumberNotSeries, N}
evaluate(a::TaylorN{T}, vals::NTuple; sorting::Bool=true) where {T<:Number} =
_evaluate(a, vals, Val(sorting))

@assert N == get_numvars()
evaluate(a::TaylorN, vals; sorting::Bool=true) = _evaluate(a, (vals...,), Val(sorting))

R = promote_type(T,S)
evaluate(a::TaylorN, v, vals...; sorting::Bool=true) =
_evaluate(a, (v, vals...,), Val(sorting))

function _evaluate(a::TaylorN{T}, vals) where {T<:Number}
@assert get_numvars() == length(vals)
R = promote_type(T,typeof(vals[1]))
a_length = length(a)
suma = zeros(R, a_length)
@inbounds for homPol in length(a):-1:1
suma[homPol] = evaluate(a.coeffs[homPol], vals)
end
return suma
end

function _evaluate(a::TaylorN{T}, vals::NTuple, ::Val{true}) where {T<:Number}
suma = _evaluate(a, vals)
return sum( sort!(suma, by=abs2) )
end

evaluate(a::TaylorN, vals) = evaluate(a, (vals...,))

evaluate(a::TaylorN, v, vals...) = evaluate(a, (v, vals...,))
function _evaluate(a::TaylorN{T}, vals::NTuple, ::Val{false}) where {T<:Number}
suma = _evaluate(a, vals)
return sum( suma )
end

function evaluate(a::TaylorN{T}, vals::NTuple{N,Taylor1{S}}) where
{T<:Number, S<:NumberNotSeries, N}
Expand Down Expand Up @@ -329,6 +332,8 @@ evaluate(A::AbstractArray{TaylorN{T}}) where {T<:Number} = evaluate.(A)
(p::TaylorN)(s::Symbol, x) = evaluate(p, s, x)
(p::TaylorN)(x::Pair) = evaluate(p, first(x), last(x))
(p::TaylorN)(x, v...) = evaluate(p, (x, v...,))
(p::TaylorN)(b::Bool, x) = evaluate(p, x, sorting=b)
(p::TaylorN)(b::Bool, x, v...) = evaluate(p, (x, v...,), sorting=b)

#function-like behavior for AbstractArray{TaylorN{T}}
if VERSION > v"1.1"
Expand Down
1 change: 0 additions & 1 deletion src/printing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ function homogPol2str(a::HomogeneousPolynomial{Taylor1{T}}) where {T<:Number}
end

function numbr2str(zz, ifirst::Bool=false)
iszero(zz) && return string( zz )
plusmin = ifelse( ifirst, string(""), string("+ ") )
return string(plusmin, zz)
end
Expand Down
10 changes: 8 additions & 2 deletions test/manyvariables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ using TaylorSeries

using Test
using LinearAlgebra
eeuler = Base.MathConstants.e

@testset "Tests for HomogeneousPolynomial and TaylorN" begin
eeuler = Base.MathConstants.e

@test HomogeneousPolynomial <: AbstractSeries
@test HomogeneousPolynomial{Int} <: AbstractSeries{Int}
@test TaylorN{Float64} <: AbstractSeries{Float64}
Expand Down Expand Up @@ -216,7 +217,7 @@ eeuler = Base.MathConstants.e
@test evaluate(xH) == zero(eltype(xH))
@test xH() == zero(eltype(xH))
@test xH([1,1]) == evaluate(xH, [1,1])
@test xH((1,1)) == 1
@test xH((1,1)) == xH(1, 1.0) == evaluate(xH, (1, 1.0)) == 1
hp = -5.4xH+6.89yH
@test hp([1,1]) == evaluate(hp, [1,1])
vr = rand(2)
Expand Down Expand Up @@ -376,6 +377,9 @@ eeuler = Base.MathConstants.e
@test exy(0.1im, 0.01im) == exp(0.11im)
@test evaluate(exy,(0.1im, 0.01im)) == exp(0.11im)
@test exy((0.1im, 0.01im)) == exp(0.11im)
@test exy(true, (0.1im, 0.01im)) == exp(0.11im)
@test evaluate(exy, (0.1im, 0.01im), sorting=false) == exy(false, (0.1im, 0.01im))
@test evaluate(exy, (0.1im, 0.01im), sorting=false) == exy(false, 0.1im, 0.01im)
@test evaluate(exy,[0.1im, 0.01im]) == exp(0.11im)
@test exy([0.1im, 0.01im]) == exp(0.11im)
@test isapprox(evaluate(exy, (1,1)), eeuler^2)
Expand All @@ -394,6 +398,8 @@ eeuler = Base.MathConstants.e
v = zeros(Int, 2)
@test evaluate!([xT, yT], ones(Int, 2), v) == nothing
@test v == ones(2)
@test evaluate!([xT, yT][1:2], ones(Int, 2), v) == nothing
@test v == ones(2)
A_TN = [xT 2xT 3xT; yT 2yT 3yT]
@test evaluate(A_TN, ones(2)) == [1.0 2.0 3.0; 1.0 2.0 3.0]
@test evaluate(A_TN) == [0.0 0.0 0.0; 0.0 0.0 0.0]
Expand Down
3 changes: 2 additions & 1 deletion test/onevariable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ using TaylorSeries

using Test
using LinearAlgebra, SparseArrays
const eeuler = Base.MathConstants.e

# This is used to check the fallack of pretty_print
struct SymbNumber <: Number
Expand All @@ -14,6 +13,8 @@ end
Base.iszero(::SymbNumber) = false

@testset "Tests for Taylor1 expansions" begin
eeuler = Base.MathConstants.e

ta(a) = Taylor1([a,one(a)],15)
t = Taylor1(Int,15)
tim = im*t
Expand Down