-
Notifications
You must be signed in to change notification settings - Fork 110
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
Specifying the output type of an interpolation object #17
Comments
Good issue to be thinking about now. +1 on having the first argument be the type, and for making it optional. This is going to be a bit rambling, as I'm thinking this through as I type. For thinking this through carefully, a good exercise is to give physical units to everything (https://github.com/Keno/SIUnits.jl). Suppose the user supplies the input array in terms meters, based on a Float32 Note that converting the input coordinates to a specified type is different (and a better choice, I think) from converting the result: it means that we don't have to worry about putting in so many manual conversions, and all the calculations should just "work out." One nasty item, though: what to do if If the user asks for something for which the appropriate conversions are absent or impossible, with these steps I think it's no longer our problem, except perhaps to think about what the error message should look like (if indeed we want to customize it---perhaps a missing method error is all we need). However, if we let users supply both, then there's a risk of broken promises:
because internally it looks like this:
So maybe we don't have the user specify the element type: maybe we have them just specify the coefficient type, and we compute the element type (which is pretty easy to do from This way of thinking has some good news: it seems reasonably safe to use
|
Just so I understand you correctly; by element type you refer to essentially I'm thinking that if we rely too much on type inference/promotion to get a good element type (by the above definitions), we might risk ending up with everything in An important aspect is that the user should not have to care about any implementation details; the type that is specified should have a clear, and explicit, place in the API. We do require of the input array Regarding sensible defaults, I think it would even be OK - at least as a first step - to default to Float64 always, and be fine with "poisoning" |
Another thought (that I'll just document here before I forget it): eventually, we'll want something like |
Also, won't all this become much easier to implement with staged functions? At least, I imagine we would have to do a lot less of the type inference reasoning ourselves... |
If we have float literals in the implementation, then yes, that's right. But we may not even need float literals, as you might see in my implementation of I suspect we can basically restrict the type reasoning to the following lines in the constructor (we could probably get away with something a little less "rigorous," but...): Interpolation{Tcoef<:Number}(::Type{Tcoef}, A, ...)
(isempty(A) || ndims(A) == 0) && error("Cannot construct an Interpolation with an empty or singleton array")
c = one(Tcoef)
for i = 2:ndims(A)
c *= c # this is the most excessively-rigorous part...
end
Tel = typeof(c*A[1] + c*A[1])
# rest of the constructor
Interpolation{Tel,N,Tcoef,...}(...)
end and then in getindex{Tel,N,Tcoef}(itp::Interpolation{Tel, N, Tcoef}, x) = getindex(itp, convert(Tcoef, x))
function getindex{Tel,N,Tcoef}(itp::Interpolation{Tel, N, Tcoef}, x::Tcoef)
# here's the real implementation
end I don't think stagedfunctions will change anything, really. (EDIT: about type-specification, I mean.) |
We'll still need literals when specifying the matrix systems for various prefiltering schemes. How do we handle possible type promotion in (pseudo) |
Yes, |
Thinking another round on it after asking for help in #19 just now, I'm starting to believe converting to I think we need to do some more bikeshedding... Given the methods defined on To make it so, we need to be careful about types in the following parts of the code:
Given the facts above, it seems that we have to make yet another separation between types, and add another type parameter to the interpolation object; a I think we can still get away with having the user specify only one (optional) type argument, namely Does this seem like a reasonable approach? |
I realize I caused a terminology confusion: I forgot there's a field called So yes, this is a reasonable approach, with one possible caveat which I may try a PR to fix. |
Now I'm beginning to wonder if we want to always use duck-typing, and just preserve whatever the user passes as an index. That would mean we can't make |
Here's the best reason to consider this: julia> function qinterp1(A, x)
ix = round(Int, real(x))
xf = x-ix
cm = 1//2 * (xf-1//2)^2
c = 3//4 - xf^2
cp = 1//2 * (xf+1//2)^2
cm*A[ix-1] + c*A[ix] + cp*A[ix+1]
end
julia> A = [(3.8-x)^2+2 for x = 1:10]
10-element Array{Float64,1}:
9.84
5.24
2.64
2.04
3.44
6.84
12.24
19.64
29.04
40.44
julia> qinterp1(A, 2.1)
5.139999999999999
julia> using DualNumbers
julia> qinterp1(A, dual(2.1,1))
5.139999999999999 - 3.4du
julia> dx = sqrt(eps())
1.4901161193847656e-8
julia> (qinterp1(A, 2.1+dx)-qinterp1(A, 2.1-dx))/(2*dx) # finite-difference estimate of the gradient
-3.4000000059604645 DualNumbers allows people to check derivatives of any functions that use interpolations internally; it's much higher-precision than finite differencing, and oh-so-much-easier to use. (Related: I notice the gradient tests are very "sloppy" with tolerances of e.g., Amplifying on my comment above: since the output type of |
A compelling argument indeed. What benefits do we have from subtyping Another argument to drop |
The first thing that occurs to me is the loss of the ability to create |
Reading about |
You may want to follow any discussion in JuliaLang/julia#9586. |
Thanks for the cross-reference; I've subscribed. The results should be interesting =) |
One of the issues with Grid.jl was that it's hard to specify what type the interpolation object should return - Interpolations.jl should be able to do better if we want it to be easily usable with any number type.
I'm leaning toward an interface with an optional first type argument, that specifies the output type, similar to what
round
and friends do in 0.4:Of course, we need to provide some sensible default, and there are a couple of options:
Use the element type of the input array, i.e.
Interpolation(A, config...) = Interpolation(eltype(A), A, config...)
Pros:
eltype(Interpolation(A,...)) == eltype(A)
Cons:
convert
each return value, so there must be a conversion defined from whatever our calculations promote to, to the return type.Use use some sensible promotion result, e.g.
promote_type(eltype(A), Float64, typeof(x)...)
(where theFloat64
is from the literals in the prefiltering step - we might be able to avoid those, if we can require aconvert
method for converting floats toeltype(A)
)Pros:
itp = Interpolation(1:10, ...)
Cons:
promote_type(Rational{Int}, Float64) == Float64
will make us return floats instead of rationals forInterpolation(A::Array{T<:Rational}, ...)
I honestly don't know what's best here, but before we start implementing this, we need some sort of decisions on:
The text was updated successfully, but these errors were encountered: