Skip to content

Commit

Permalink
Overflow error when hashtables are inconsistent (#314)
Browse files Browse the repository at this point in the history
* Throw OverflowError when index_tables is negative

* Fix is error message and addtests

* Mention the error and in_base_safe to docs

* Minor fix in tests

* Bump patch version
  • Loading branch information
lbenet authored Feb 18, 2023
1 parent 3a96af4 commit 1daed03
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "TaylorSeries"
uuid = "6aa5eb33-94cf-58f4-a9d0-e4b2c4fc25ea"
repo = "https://github.com/JuliaDiff/TaylorSeries.jl.git"
version = "0.13.0"
version = "0.13.1"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
1 change: 1 addition & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ _InternalMutFuncs
generate_tables
generate_index_vectors
in_base
in_base_safe
make_inverse_dict
resize_coeffs1!
resize_coeffsHP!
Expand Down
36 changes: 20 additions & 16 deletions docs/src/userguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ t = shift_taylor(0.0) # Independent variable `t`
```

!!! warning
The information about the maximum order considered is displayed using a big-𝒪 notation.
The information about the maximum order considered is displayed using a big-𝒪 notation.
The convention followed when different orders are combined, and when certain functions
are used in a way that they reduce the order (like [`differentiate`](@ref)), is to be consistent
with the mathematics and the big-𝒪 notation, i.e., to propagate the lowest order.
In some cases, it is desirable to not display the big-𝒪 notation. The function [`displayBigO`](@ref)
are used in a way that they reduce the order (like [`differentiate`](@ref)), is to be consistent
with the mathematics and the big-𝒪 notation, i.e., to propagate the lowest order.

In some cases, it is desirable to not display the big-𝒪 notation. The function [`displayBigO`](@ref)
allows to control whether it is displayed or not.
```@repl userguide
displayBigO(false) # turn-off displaying big O notation
Expand All @@ -78,14 +78,14 @@ The definition of `shift_taylor(a)` uses the method
[`Taylor1([::Type{Float64}], order::Int)`](@ref), which is a
shortcut to define the independent variable of a Taylor expansion,
of given type and order (the default is `Float64`).
Defining the independent variable in advance is one of the easiest
Defining the independent variable in advance is one of the easiest
ways to use the package.

The usual arithmetic operators (`+`, `-`, `*`, `/`, `^`, `==`) have been
extended to work with the [`Taylor1`](@ref) type, including promotions that
involve `Number`s. The operations return a valid Taylor expansion, consistent
with the order of the series. This is apparent in the penultimate example
below, where the fist non-zero coefficient is beyond the order of the expansion,
with the order of the series. This is apparent in the penultimate example
below, where the fist non-zero coefficient is beyond the order of the expansion,
and hence the result is zero.

```@repl userguide
Expand All @@ -100,9 +100,9 @@ t^6 # t is of order 5
t^2 / t # The result is of order 4, instead of 5
```

Note that the last example returns a `Taylor1` series of order 4, instead
of order 5; this is be consistent with the number of known coefficients of the
returned series, since the result corresponds to factorize `t` in the numerator
Note that the last example returns a `Taylor1` series of order 4, instead
of order 5; this is be consistent with the number of known coefficients of the
returned series, since the result corresponds to factorize `t` in the numerator
to cancel the same factor in the denominator.

If no valid Taylor expansion can be computed an error is thrown, for instance,
Expand All @@ -121,8 +121,8 @@ are `exp`, `log`, `sqrt`, the trigonometric functions
`sinh`, `cosh` and `tanh` and their inverses;
more functions will be added in the future. Note that this way of obtaining the
Taylor coefficients is not a *lazy* way, in particular for many independent
variables. Yet, the implementation is efficient enough, especially for the
integration of ordinary differential equations, which is among the
variables. Yet, the implementation is efficient enough, especially for the
integration of ordinary differential equations, which is among the
applications we have in mind (see
[TaylorIntegration.jl](https://github.com/PerezHz/TaylorIntegration.jl)).

Expand Down Expand Up @@ -152,7 +152,7 @@ getcoeff(expon, 0) == expon[0]
rationalize(expon[3])
```

Note that certain arithmetic operations, or the application of some functions,
Note that certain arithmetic operations, or the application of some functions,
may change the order of the result, as mentioned above.
```@repl userguide
t # order 5 independent variable
Expand All @@ -164,7 +164,7 @@ sqrt(t^2) # returns an order 2 series expansion
Differentiating and integrating is straightforward for polynomial expansions in
one variable, using [`differentiate`](@ref) and [`integrate`](@ref). (The
function [`derivative`](@ref) is a synonym of `differentiate`.) These
functions return the corresponding [`Taylor1`](@ref) expansions.
functions return the corresponding [`Taylor1`](@ref) expansions.
The order of the derivative of a `Taylor1` is reduced by 1.
For the integral, an integration constant may be
set by the user (the default is zero); the order of the integrated polynomial
Expand Down Expand Up @@ -199,7 +199,7 @@ eBig = evaluate( exp(tBig), one(BigFloat) )
ℯ - eBig
```

Another way to evaluate the value of a `Taylor1` polynomial `p` at a given value `x`,
Another way to evaluate the value of a `Taylor1` polynomial `p` at a given value `x`,
is to call `p` as if it was a function, i.e., `p(x)`:

```@repl userguide
Expand Down Expand Up @@ -281,6 +281,10 @@ by `set_variables` initially.
get_variables(2) # vector of independent variables of order 2
```

!!! warning
An `OverflowError` is thrown when the construction of the internal tables is not
fully consistent, avoiding silent errors; see [issue #85](https://github.com/JuliaDiff/TaylorSeries.jl/issues/85).

The function [`show_params_TaylorN`](@ref) displays the current values of the
parameters, in an info block.

Expand Down
22 changes: 21 additions & 1 deletion src/hash_tables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ of the corresponding monomial in `coeffs_table`.
function generate_tables(num_vars, order)
coeff_table = [generate_index_vectors(num_vars, i) for i in 0:order]

index_table = Vector{Int}[map(x->in_base(order, x), coeffs) for coeffs in coeff_table]
index_table = Vector{Int}[map(x->in_base_safe(order, x), coeffs) for coeffs in coeff_table]

pos_table = map(make_inverse_dict, index_table)
size_table = map(length, index_table)
Expand Down Expand Up @@ -91,13 +91,33 @@ function in_base(order, v)

result = 0

all(iszero.(v)) && return result

for i in v
result = result*order + i
end

result
end

"""
in_base_safe(order, v)
Same as `in_base` assuring positivity of the result;
used for constructing `index_table`.
"""
function in_base_safe(order, v)
result = in_base(order, v)

iszero(v) && return result

(result <= 0) && throw(OverflowError("""
Using numvars=$(length(v)) at order=$(order) produces
a non-positive index_table entry: $result."""))

return result
end


const coeff_table, index_table, size_table, pos_table =
generate_tables(get_numvars(), get_order())
Expand Down
2 changes: 1 addition & 1 deletion test/intervals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ eeuler = Base.MathConstants.e
@test diam(g1(-1..1)) < diam(gt(ii))

# Test display for Taylor1{Complex{Interval{T}}}
vc = [complex(1.5 .. 2, 0 ), complex(-2 .. -1, -1 .. 1 ),
vc = [complex(1.5 .. 2, 0..0 ), complex(-2 .. -1, -1 .. 1 ),
complex( -1 .. 1.5, -1 .. 1.5), complex( 0..0, -1 .. 1.5)]
displayBigO(false)
@test string(Taylor1(vc, 5)) ==
Expand Down
29 changes: 22 additions & 7 deletions test/manyvariables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,26 @@ using TaylorSeries
using Test
using LinearAlgebra

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

@test HomogeneousPolynomial <: AbstractSeries
@test HomogeneousPolynomial{Int} <: AbstractSeries{Int}
@test TaylorN{Float64} <: AbstractSeries{Float64}

@testset "Test hash tables" begin
set_variables("x", numvars=2, order=6)
_taylorNparams = TaylorSeries.ParamsTaylorN(6, 2, String["x₁", "x₂"])
@test _taylorNparams.order == get_order()
@test _taylorNparams.num_vars == get_numvars()
@test _taylorNparams.variable_names == get_variable_names()
@test _taylorNparams.variable_symbols == get_variable_symbols()

@test_throws OverflowError("""
Using numvars=65 at order=1 produces
a non-positive index_table entry: 0.""") set_variables("δ", order=1, numvars=65)
@test_throws OverflowError("""
Using numvars=41 at order=2 produces
a non-positive index_table entry: -6289078614652622815.""") set_variables("δ", order=2, numvars=41)
@test_throws OverflowError("""
Using numvars=32 at order=3 produces
a non-positive index_table entry: -9223372036854775808.""") set_variables("δ", order=3, numvars=32)
set_variables("x", numvars=2, order=40)
@test all(allunique.(TS.index_table[:]))

@test eltype(set_variables(Int, "x", numvars=2, order=6)) == TaylorN{Int}
@test eltype(set_variables("x", numvars=2, order=6)) == TaylorN{Float64}
@test eltype(set_variables(BigInt, "x y", order=6)) == TaylorN{BigInt}
Expand All @@ -35,7 +41,16 @@ using LinearAlgebra
@test TaylorSeries.index_table[2][1] == 7
@test TaylorSeries.in_base(get_order(),[2,1]) == 15
@test TaylorSeries.pos_table[4][15] == 2
end

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

@test HomogeneousPolynomial <: AbstractSeries
@test HomogeneousPolynomial{Int} <: AbstractSeries{Int}
@test TaylorN{Float64} <: AbstractSeries{Float64}

set_variables([:x,:y], order=6)
@test get_order() == 6
@test get_numvars() == 2

Expand Down

2 comments on commit 1daed03

@lbenet
Copy link
Member Author

@lbenet lbenet commented on 1daed03 Feb 18, 2023

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.

Registration pull request created: JuliaRegistries/General/77990

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.13.1 -m "<description of version>" 1daed03049a6f0c9079628dc66c84e74ba5b352f
git push origin v0.13.1

Please sign in to comment.