-
Notifications
You must be signed in to change notification settings - Fork 53
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 function-like behavior for Taylor1, TaylorN, HomogeneousPolynomial #118
Conversation
PR tests are passing, if there is anything that I missed or that you think should be added, please let me know 😄 |
It would be a nice feature to take advantage of this PR to implement an evaluate method for an array of values. I'm thinking of something like julia> using TaylorSeries
julia> import TaylorSeries: evaluate;
julia> function evaluate(p::Taylor1{T},x::Vector{S}) where {T<:Number,S<:Number}
ll = length(x)
p_eval = zeros(x)
for (i,xi) in enumerate(x)
@inbounds p_eval[i] = evaluate(p,xi)
end
return p_eval
end
julia> (p::Taylor1)(x) = evaluate(p,x) #this now works for numbers & arrays!!
julia> p = Taylor1([1,2,3,4])
1 + 2 t + 3 t² + 4 t³ + 𝒪(t⁴)
julia> p(1.0)
10.0
julia> p([1.0,0.0])
2-element Array{Float64,1}:
10.0
1.0 The analogous could be done for |
I agree that this functionality should be available for the cases you mention, @blas-ko! Granted, I didn't add the methods you are proposing; but actually, as the way it is now, such cases may already be handled via broadcasting: #evaluating p at a matrix of Float64s:
julia> p.([1.0 0.0; -1.0 -2.0])
2×2 Array{Float64,2}:
10.0 1.0
-2.0 -23.0
#evaluating p at a 3x3x3 matrix of Float64s:
julia> p.(rand(3,3,3))
3×3×3 Array{Float64,3}:
[:, :, 1] =
8.65957 1.17927 8.12569
1.13276 2.57914 3.37285
2.51999 5.42389 2.04953
[:, :, 2] =
1.03394 1.19053 3.51668
1.15536 9.98952 4.27719
7.29441 2.3461 2.76938
[:, :, 3] =
1.33343 1.11886 1.08465
5.75461 1.47925 1.78689
1.47734 2.19666 1.84005 and for TaylorNs: julia> ξ1, ξ2 = set_variables("ξ", numvars=2, order=15);
julia> f = sin(ξ1+ξ1*ξ2); g = exp(-sin(ξ1)+ξ1*ξ2); h = [f, g];
#evaluating f. at a vector of evaluation points returns a vector of Float64 values:
julia> f.([rand(2),rand(2)])
2-element Array{Float64,1}:
0.974375
0.585455
#evaluating g. at a 2x2 matrix of evaluation points returns a 2x2 matrix of Float64 values:
julia> g.( map(x->rand(2), rand(2,2)) )
2×2 Array{Float64,2}:
0.929124 0.932631
0.825413 0.888743
#evaluating h=[f,g] at a 2x2 matrix of evaluation points returns a 2x2 matrix of Vector{Float64}(2) values:
julia> h.( map(x->rand(2), rand(2,2)) )
2×2 Array{Array{Float64,1},2}:
[0.674398, 0.736717] [0.991339, 0.994949]
[0.865741, 0.959931] [0.460701, 0.800402]
#and so on...
julia> h.( [rand(2),rand(2)] )
2-element Array{Array{Float64,1},1}:
[0.748772, 0.728316]
[0.165423, 0.964655]
julia> h.( map(x->rand(2), rand(3,2,2)) )
3×2×2 Array{Array{Float64,1},3}:
[:, :, 1] =
[0.970154, 0.996443] [0.952156, 0.628598]
[0.434873, 0.979518] [0.750666, 0.492932]
[0.839201, 0.475184] [0.151065, 0.894432]
[:, :, 2] =
[0.966398, 0.597349] [0.414589, 0.901062]
[0.045531, 0.992213] [0.58178, 0.701201]
[0.395325, 0.718587] [0.951338, 0.66144] I think this is, in a sense, more julian, but also more general; otherwise one would have to define a method for each particular case... The only caveat is that EDIT: Sorry for the mistake, just tried these examples on julia 0.5.2 and they worked too! |
So, for the particular case case of Taylor1 it might be enough to define: evaluate{T<:Number,S<:Number}(p::Taylor1{T},x::Vector{S}) = evaluate.(p,x) Thus julia> p = Taylor1(rand(10))
julia> vr = rand(5)
julia> p(vr) == p.(vr)
true
julia> p(vr) == evaluate.(p,vr)
true I'm gonna push this extra method for Taylor1s and corresponding tests! Thanks @blas-ko for your suggestion! I'd like to use some similar broadcasting tricks for TaylorN, but then the second argument would have to be a |
Is there an easy way to convert from a |
You're absolutely right, my fault there!
Maybe julia> a = [[1,2,3],[4,5,6]];
julia> @time hcat(a...)
0.000038 seconds (8 allocations: 384 bytes)
3×2 Array{Int64,2}:
1 1
1 1
2 3 |
Many thanks, @blas-ko! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm in favor of merging this.
I have two questions:
-
Is everything type stable? It seems to me that this is the case...
-
What about mixed-types, i.e.
Taylor1{TaylorN{T}}
, orTaylorN{Taylor1{T}}
?
Well, as this functionality is being proposed right now, the function-like behavior of Taylor1, etc., at the end of the day relies on
I'm gonna add some tests for the mixtures! That's actually something important that I didn't add! 😅 sorry about that! Regarding the function-like behavior for mixtures, this again relies on |
Thanks for all your comments @lbenet! I actually had to tweak a bit some parts of |
2 similar comments
2 similar comments
@lbenet @dpsanders there was a weird error on travis job#652.5, could you please help me restart it? otherwise, tests are passing |
I restarted the job. Actually, with the syntax t(3) to evaluate, is there now any need for the function called evaluate? |
Thanks, David!
Well, currently |
The last commit addresses more mixture cases, such as evaluating a |
Probably we should keep I just restarted one test that hung. |
I agree!
Many thanks, @lbenet! |
Sure! I added some general details about this new behavior in the User's Guide section of the docs. I was also thinking that I should add some docstrings, but I was thinking whether I should add those in the I'm asking this because, as I understood from JuliaDocs/Documenter.jl#228 and JuliaDocs/Documenter.jl#290, currently it is not possible to write docstrings for these kinds of methods, and the recommended approach mentioned there is to document within the type's docstring that objects of that type are callable and provide a usage example there. So, how would you recommend me to proceed? |
I've updated the docstrings for |
EDIT: Sorry, "job |
Tests are now passing! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While everyhting appears to be ok, I have some comments.
src/evaluate.jl
Outdated
@@ -88,8 +97,25 @@ function evaluate{T<:Number}(a::Taylor1{T}, x::Taylor1{T}) | |||
end | |||
suma | |||
end | |||
function evaluate{T<:NumberNotSeries}(a::Taylor1{Taylor1{T}}, x::Taylor1{T}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NumberNotSeries
here may be too restrictive; I'm thinking in cases such as Taylor1{Taylor1{...{T}...}
. Would everything work if T<:Number
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, it should work! Thanks!
src/evaluate.jl
Outdated
evaluate{T<:Number}(a::TaylorN{T}) = a[1][1] | ||
|
||
function evaluate{T<:Number}(x::Array{TaylorN{T},1}, δx::Array{T,1}) | ||
x0 = Array{T}( length(x) ) | ||
evaluate!( x, δx, x0 ) | ||
return x0 | ||
end | ||
|
||
function evaluate{T<:NumberNotSeries}(x::Array{TaylorN{T},1}, δx::Array{Taylor1{T},1}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I think the two following methods can be written as one, using T<:NumberNotSeriesN
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌Great! Thanks!
@@ -100,6 +126,25 @@ function evaluate!{T<:Number}(x::Array{TaylorN{T},1}, δx::Array{T,1}, | |||
end | |||
nothing | |||
end | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @lbenet!
@lbenet: just pushed the changes you suggested; tests are passing locally on 0.5.2, 0.6.0, and 0.7.0-DEV and are running on travis right now. Again, many thanks! |
Thanks a lot for your contribution! I am merging it right now! |
I was just checking evaluation and it seems that broadcasting is pretty slow; check the following julia> using TaylorSeries; import TaylorSeries: evaluate
julia> function evaluate{T<:Number}(a::Taylor1{T},vals::Vector{T})
ll = length(vals)
sumas = zeros(T,ll)
for i in 1:ll
sumas[i] = evaluate(a,vals[i])
end
return sumas
end
evaluate (generic function with 15 methods)
julia> function evaluate{T<:Number,S<:Number}(a::Taylor1{T},vals::Vector{S})
ll = length(vals)
R = promote_type(S,T)
sumas = zeros(R,ll)
for i in 1:ll
sumas[i] = evaluate(a,vals[i])
end
return sumas
end
evaluate (generic function with 16 methods)
julia> t = Taylor1(10); a = collect(0.:0.5:10);
julia> using BenchmarkTools
julia> @btime evaluate(t,a); @btime evaluate.(t,a);
402.035 ns (1 allocation: 256 bytes)
7.380 μs (26 allocations: 1.31 KiB) I've not done this with the other cases, but in this particular case the difference is yuuuge. Maybe it's worth it to write the specific methods for evaluating in vectors or matrices. |
@blas-ko I just merged this PR, seemingly at the same time you wrote your comment, though I was a bit faster ;-). You are right that broadcasting (here) incurs in some allocations that cost time, roughly a factor 18. Note that julia> @which evaluate.(t,a)
broadcast(f, A, Bs...) in Base.Broadcast at broadcast.jl:434 so my guess is that internally |
JuliaDiff#118) * Add function-like behavior for Taylor1 * Relocate new code * Add function-like behavior for TaylorN * Fix TaylorN functor methods * Add tests for Taylor1 * Add more Taylor1 tests * Add TaylorN tests; more Taylor1 tests; add missing evaluate methods * Add function-like behavior for HomogeneousPolynomial and corresponding tests * Add missing tests for HomogeneousPolynomial * Add another test for Taylor1s * Fix test * Add extra evaluate method for Taylor1 (suggested by @blas-ko) * Add an evaluate test for mixtures (more to come) * Add tests for mixtures; add/fix evaluate methods * A small fix * Add missing evaluate methods for mixtures and tests * Update docs * Add evaluate method and tests * Fix new method * Update docstrings * Changes suggested by @lbenet 's review
JuliaDiff#118) * Add function-like behavior for Taylor1 * Relocate new code * Add function-like behavior for TaylorN * Fix TaylorN functor methods * Add tests for Taylor1 * Add more Taylor1 tests * Add TaylorN tests; more Taylor1 tests; add missing evaluate methods * Add function-like behavior for HomogeneousPolynomial and corresponding tests * Add missing tests for HomogeneousPolynomial * Add another test for Taylor1s * Fix test * Add extra evaluate method for Taylor1 (suggested by @blas-ko) * Add an evaluate test for mixtures (more to come) * Add tests for mixtures; add/fix evaluate methods * A small fix * Add missing evaluate methods for mixtures and tests * Update docs * Add evaluate method and tests * Fix new method * Update docstrings * Changes suggested by @lbenet 's review
* Added function and macro `taylor_expand` for expanding arbitraty functions. * Deleted macros and set order as keyword argument so methods doesnt clash `taylor_expand(f,x0::Int64)` and `taylor_expand(f,order)` clashed. * Added some tests for `taylor_expand`. * un-exported taylor_expand macros. * Updated taylor_expand tests. * Added taylor_expand method for TaylorN and warning if number of variables is changed. * Fix travis issue for taylor_expand (hopefully). * Added taylor_expand! and tests for Taylor1. Followed suggestion from @lbenet. * Add function-like behavior for Taylor1, TaylorN, HomogeneousPolynomial (#118) * Add function-like behavior for Taylor1 * Relocate new code * Add function-like behavior for TaylorN * Fix TaylorN functor methods * Add tests for Taylor1 * Add more Taylor1 tests * Add TaylorN tests; more Taylor1 tests; add missing evaluate methods * Add function-like behavior for HomogeneousPolynomial and corresponding tests * Add missing tests for HomogeneousPolynomial * Add another test for Taylor1s * Fix test * Add extra evaluate method for Taylor1 (suggested by @blas-ko) * Add an evaluate test for mixtures (more to come) * Add tests for mixtures; add/fix evaluate methods * A small fix * Add missing evaluate methods for mixtures and tests * Update docs * Add evaluate method and tests * Fix new method * Update docstrings * Changes suggested by @lbenet 's review * Added method for evaluating a TaylorN with an array of TaylorNs. * Added taylor_expand! method for TaylorN * Added some test for taylor_expand! * Documentation for taylor_expand and taylor_expand! * Added function and macro `taylor_expand` for expanding arbitraty functions. * Deleted macros and set order as keyword argument so methods doesnt clash `taylor_expand(f,x0::Int64)` and `taylor_expand(f,order)` clashed. * Added some tests for `taylor_expand`. * un-exported taylor_expand macros. * Updated taylor_expand tests. * Added taylor_expand method for TaylorN and warning if number of variables is changed. * Fix travis issue for taylor_expand (hopefully). * Added taylor_expand! and tests for Taylor1. Followed suggestion from @lbenet. * Add function-like behavior for Taylor1, TaylorN, HomogeneousPolynomial (#118) * Add function-like behavior for Taylor1 * Relocate new code * Add function-like behavior for TaylorN * Fix TaylorN functor methods * Add tests for Taylor1 * Add more Taylor1 tests * Add TaylorN tests; more Taylor1 tests; add missing evaluate methods * Add function-like behavior for HomogeneousPolynomial and corresponding tests * Add missing tests for HomogeneousPolynomial * Add another test for Taylor1s * Fix test * Add extra evaluate method for Taylor1 (suggested by @blas-ko) * Add an evaluate test for mixtures (more to come) * Add tests for mixtures; add/fix evaluate methods * A small fix * Add missing evaluate methods for mixtures and tests * Update docs * Add evaluate method and tests * Fix new method * Update docstrings * Changes suggested by @lbenet 's review * Added method for evaluating a TaylorN with an array of TaylorNs. * Added taylor_expand! method for TaylorN * Added some test for taylor_expand! * Documentation for taylor_expand and taylor_expand! * Corrected silly mistake from rebasing. * Rearanged taylor_expand tests to another place. They use set_variables internally. * called coeff_table directly so it doesn't make a copy. * changed docs for taylor_expand * Changed taylor_expand for TaylorN. * It doesn't use set_variables() anymore. * typeof(x0) is preserved if possible. * Changed taylor_expand! for update! * Added 1 more test... * Little performance and compatibility fix for taylor_expand
This PR implements a solution for #116, and adds corresponding tests; tests are passing on my fork, thanks everyone for your feedback!