The new inlining of small powers is incorrect e.g. for interval arithmetic, where e.g. x^2
for x
an Interval
is not the same as x*x
, and is defined using a completely separate code path.
E.g.:
using ValidatedNumerics
julia> x = -3..2 # interval from -3 to 2
[-3, 2]
julia> x^2
[-6, 9]
julia> n = 2; x^n
[0, 9]
julia> x*x
[-6, 9]
cc @stevengj
You should be able to recover the behavior you want by importing ^
and defining ^{p}(x::ValidatedNumerics.Interval, ::Type{Val{p}}) = x^p
.
Yes, that works, thanks.
Still, it is counterintuitive that I should have to do that.
Haven't we always had a default definition of x^integer
that computes x*x
for x^2
? What was happening before?
I imagine this is probably happening because all of the specialized methods for ^
on Interval
types had a concrete type for the second argument, such that the fallbacks were never called before. If there's no method ^(::Interval, ::Any)
or ^{p}(::Interval, ::Type{Val{p}})
then the generic fallback will now be called. At least that's what seems to be happening at a glance.
edit: that's not quite right, there are some methods that have an abstract type for the second argument, but you get the idea.
cc @stevengj
Probably this should be closed as a WONTFIX. x^2
before defaulted to x*x
. It still defaults to x*x
, so nothing has changed with regards to "correctness". The difference is that if you need to override this behavior you may need to override two methods of ^
instead of one.
This is the price that we pay for the opportunity for compile-time specialization and modified type computations for literal powers — we knew that going into this experiment. What we will find out in 0.6 is how many people get affected negatively by this; interval arithmetic is one such case. Hopefully there aren't too many others.
(I should also point out that x^2 = x*x
is not technically "incorrect" for interval arithmetic. It just leads to overly pessimistic intervals, not wrong intervals, because of the dependency problem.)
An alternative would be to restrict the inlining of literal powers to hardware numeric types + complex numbers thereof, which gain the most from this.
An interface where you have to know about and define two different methods in order to get a consistent specialization across two subtly different caller contexts seems to be troublesome in general. It's nice to provide the ability to override behaviors when you know the value of the exponent at compile-time, but could we structure the dispatch in a way that only base types avoid calling ^(x, ::Int)
?
I thought the old behaviour was a codegen optimization for machine types?
Confirmed fixed, many thanks!
Most helpful comment
An interface where you have to know about and define two different methods in order to get a consistent specialization across two subtly different caller contexts seems to be troublesome in general. It's nice to provide the ability to override behaviors when you know the value of the exponent at compile-time, but could we structure the dispatch in a way that only base types avoid calling
^(x, ::Int)
?