-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
RFC: tests for dimensional correctness of Base #20484
Conversation
CC @ajkeller34 |
I know some of the LU factorization code is dimensionally inconsistent, and I'd love for Unitful to work better with linear algebra. See Unitful #46. I actually have a local branch of Unitful where I was playing around with how far I could get without changing Base, and I think I got stuck somewhere, so I will try to recall what the problem was. Edit: Of course, I recognize some of this may not be trivial, and it may be better to do some prototyping in a package, which is sort of what I had in mind originally. I just thought I would mention it while the topic is being discussed. |
@ajkeller34 We discussed this long time ago in #7623. As such, the algorithm used in julia> a = [1.0u"N" 2.0u"N"
3.0u"N" 1.0u"N"]
2×2 Array{Quantity{Float64, Dimensions:{𝐋 𝐌 𝐓^-2}, Units:{N}},2}:
1.0 N 2.0 N
3.0 N 1.0 N
julia> lufact!(Matrix{Number}(a), Val{false})
Base.LinAlg.LU{Number,Array{Number,2}}(Number[1.0 N 2.0 N; 3.0 -5.0 N],[1,2],0) but this is not really satisfying. We could try experimenting with widening of the type as the factorization progresses similarly to |
For Cholesky factorization there's a good argument that |
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.
Looks like a few typos
test/dimensionful.jl
Outdated
Base.abs{p,T}(x::Furlong{p,T}) = Furlong{p,T}(abs(x.val)) | ||
|
||
for f in (:isfinite, :isnan, :isreal) | ||
@eval Base.$f(x::Furlong) = isfinite(x.val) |
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.
Should be @eval Base.$f(x::Furlong) = $f(x.val)
?
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.
Yes.
test/dimensionful.jl
Outdated
@eval Base.$f(x::Furlong) = isfinite(x.val) | ||
end | ||
for f in (:real,:imag,:complex) | ||
@eval Base.$f{p,T}(x::Furlong{p,T}) = Furlong{p}(f(x.val)) |
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.
Should be @eval Base.$f{p,T}(x::Furlong{p,T}) = Furlong{p}($f(x.val))
?
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.
Right.
Hmm, found another problem: the function colon{T}(start::T, step, stop::T)
T′ = typeof(start+step)
StepRange(convert(T′,start), step, convert(T′,stop))
end I'm not really sure why |
Hmm, for dimensionful quantities it looks like it would be nice to have |
That case handles ordinal types, e.g. |
Another case is with |
I fixed a couple more dimensional problems. My inclination would be to merge these tests and fixes now, assuming tests are green, and put additional fixes in subsequent PRs. |
What's wrong with |
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.
See issues regarding ranges. I wonder if it would be better to move the code that defines Furlong
and its operations into TestHelpers
?
base/range.jl
Outdated
@@ -6,9 +6,9 @@ colon{T<:Real}(start::T, stop::T) = UnitRange{T}(start, stop) | |||
|
|||
range(a::Real, len::Integer) = UnitRange{typeof(a)}(a, oftype(a, a+len-1)) | |||
|
|||
colon{T}(start::T, stop::T) = colon(start, oftype(stop-start, 1), stop) | |||
colon{T}(start::T, stop::T) = colon(start, oneunit(stop-start), stop) |
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.
Sorry I didn't look at this earlier. I think the original version was correct, and that this version is a bug. This has been discussed elsewhere and there isn't a uniform opinion, but I would find the following worrisome:
xmm, ymm = 1000mm, 2000mm
xm, ym = convert(Meter, xmm), convert(Meter, ymm)
xmm == xm && ymm == ym => true
(xmm:ymm) == (xm:ym) => false
I think it's a bad idea to allow start:stop
constructors for unitful quantities; one should be required to specify the step
explicitly. The oftype
version of this code forces that.
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.
Okay.
base/range.jl
Outdated
@@ -46,7 +49,7 @@ _range{T,S}(::Any, ::Any, a::T, step::S, len::Integer) = StepRangeLen{typeof(a+0 | |||
|
|||
# AbstractFloat specializations | |||
colon{T<:AbstractFloat}(a::T, b::T) = colon(a, T(1), b) | |||
range(a::AbstractFloat, len::Integer) = range(a, oftype(a, 1), len) | |||
range(a::AbstractFloat, len::Integer) = range(a, oneunit(a), len) |
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.
Here too.
test/dimensionful.jl
Outdated
end | ||
Base.sqrt{p,T}(x::Furlong{p,T}) = _div(sqrt(x.val), x, Val{2}) | ||
|
||
@test collect(Furlong(2):Furlong(10)) == collect(Furlong(2):Furlong(1):Furlong(10)) == Furlong.(2:10) |
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.
Turn the first of these into a @test_throws
|
Why would the additive identity not have units? julia> using Unitful
julia> using Unitful.m
julia> x = 1m
1 m
julia> zero(x)
0 m
julia> x + zero(x)
1 m |
Oh right, my mistake! 🥇 |
The only problem with |
But probably if you are doing the |
df10330
to
8871684
Compare
Rebased. Good to squash/merge when green? |
…d canonicalize exponents
…in TestHelpers and split tests into the relevant files, use x < zero(x) rather than x < 0 in sqrtm
8871684
to
466dc70
Compare
Rebased again. |
this has caused the ambiguity test to start segfaulting. happens often on the buildbots, and it's reproducible locally with |
This PR (currently very incomplete) adds a test suite
dimensionful.jl
that implements a small dimensionful number typeFurlong
that can be used to test the dimensional correctness of Base functions.I already caught an bug in
range
, and there are probably lots more problems.cc @timholy