-
Notifications
You must be signed in to change notification settings - Fork 149
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
Julia 0.6 rewrite #121
Julia 0.6 rewrite #121
Conversation
This is amazing. Thank you! |
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.
Epic effort!
I've only got down to indexing.jl so far, but wanted to send some comments through as it looks like I won't finish reading this today.
src/MMatrix.jl
Outdated
@inline ones{N,M}(::Type{MMatrix{N,M}}) = ones(MMatrix{N,M,Float64}) | ||
#@inline eye{N,M}(::Type{MMatrix{N,M}}) = eye(MMatrix{N,M,Float64}) | ||
#@inline zeros{N,M}(::Type{MMatrix{N,M}}) = zeros(MMatrix{N,M,Float64}) | ||
#@inline ones{N,M}(::Type{MMatrix{N,M}}) = ones(MMatrix{N,M,Float64}) |
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.
Are these obsolete, or forgotten? Ditto for the same thing in other files.
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.
Yeah, probably should delete these.
What happened here is that I made the generic versions of these functions a bit more powerful.
@pure Size(::SUnitRange{Start, End}) where {Start,End} = Size(End-Start+1) | ||
|
||
@pure @propagate_inbounds function getindex(x::SUnitRange{Start,End}, i::Int) where {Start, End} | ||
@boundscheck if i < Start || i > 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.
I have a vague memory that @boundscheck
wasn't reliable with a general expression. It does work with a function call as the expression.
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.
Maybe worth looking into. Though I thought this pattern was used throughout Base
.
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.
It is, but I think it's usually written as
@boundscheck checkbounds(A, i)
or something. IIRC I had problems when the expression given to @boundscheck
wasn't a function call.
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.
So it looks like you've defined a static version of what I'm calling an IdentityRange
or IdempotentRange
, see JuliaArrays/IdentityRanges.jl#1 and JuliaLang/julia#21052. Just to check, you're aware that these are non-1 indices arrays you've defined here? If this is intentional, you should definitely define the indices
function for them.
If that's not what you're intending, you should be checking against 1 <= i <= End - Start + 1
and then return i + Start - 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.
Haha thanks @timholy - these definitely are WIP. I think I'll split this off and put it on a branch for now.
These are just meant to be singleton array types, so that indices(SVector(1,2,3)) === SUnitRange{1,3}()
. AFAICT IdentityRanges
are meant to be a bit like a safe :
? (How is it distinct from start:stop
?)
I suppose that OneTo
has been able to double-up for both purposes, for one-based arrays?
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.
IdentityRanges are indeed a generalization of :
, one that allows you to slice some or all of an axis while preserving the indices. As to how it differs from start:stop
...if you're constructing a view v = view(a, s)
with an AbstractVector s
, the key identity is that v[i] == a[s[i]]
. Since start:stop
is a conventional UnitRange
, it is indexed starting at 1, so v = view(a, start:stop)
would be indexed starting at 1 no matter how a
is indexed. In contrast, v = view(a, IdentityRange(start:stop))
would be indexed starting with start
, no matter how a
is indexed.
end | ||
|
||
@inline (::Type{Scalar{T}}){T}(x::Tuple{T}) = Scalar{T}(x[1]) | ||
@inline Scalar(x::Tuple{T}) where {T} = Scalar{T}(x[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.
What's this indexing x[1]
about?
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.
The abstract constructors will go Scalar(x) -> Scalar((x,))
(the internal functions also give a tuple). This then goes to Scalar{T}(x::T)
, which is an inner constructor (and is more specific than other constructors).
# mutable things stay mutable | ||
similar_type{SA<:Union{MVector,MMatrix,MArray},T,S}(::Type{SA},::Type{T},s::Size{S}) = mutable_similar_type(T,s,length_val(s)) | ||
# should mutable things stay mutable? | ||
#similar_type{SA<:Union{MVector,MMatrix,MArray},T,S}(::Type{SA},::Type{T},s::Size{S}) = mutable_similar_type(T,s,length_val(s)) |
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.
Is the behavior changed here?
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. I forgot to mention above. @timholy seemed supportive, so I left it this way.
src/abstractarray.jl
Outdated
end | ||
@inline reshape(a::StaticArray, s::Size) = similar_type(a, s)(Tuple(a)) | ||
@generated function reshape(a::AbstractArray, s::Size{S}) where {S} | ||
if IndexStyle(a) == IndexLinear() # TODO this isn't "hyperpure" |
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.
But this is a TODO, because IndexStyle
isn't really supported yet?
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.
Actually, this one is critical. If a
is defined after using StaticArrays
, this will fail.
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.
Can you make this safer by dispatching on the IndexStyle
in "regular" functions?
reshape(a::AbstractArray, s::Size) = _reshape(IndexStyle(a), a, s)
@generated function _reshape(::IndexLinear, a, s::Size{S}) where {S}
...
end
@generated function _reshape(::IndexStyle, a, s::Size{S}) where {S}
...
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.
Will do :)
end | ||
end | ||
j += 1 | ||
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.
This loop looks exactly the same as in broadcast
, with the exception of the dest[$j] =
bit. Could be factored together?
src/convert.jl
Outdated
end | ||
return out | ||
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.
What's all this commented out stuff? Speculative functionality? Removed stuff?
src/det.jl
Outdated
@inbounds return A[1]*A[4] - A[3]*A[2] | ||
end | ||
|
||
@inline function _det{T<:Unsigned}(::Size{(2,2)}, A::AbstractMatrix{T}) | ||
@inline function _det(::Size{(2,2)}, A::StaticMatrix{T}) where {T <: Unsigned} |
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.
Can this where
be avoided with StaticMatrix{<:Unsigned}
?
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, it can
src/det.jl
Outdated
if istriu(A) || istril(A) | ||
return convert($T2, det(UpperTriangular(A)))::$T2 # Is this a Julia bug that a convert is not type stable?? | ||
return convert(T2, det(UpperTriangular(A))) # Is this a Julia bug that a convert is not type stable?? |
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.
The type assert was removed here. Obsolete comment?
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.
ahh... I probably should test this...
@@ -190,7 +193,7 @@ end | |||
# A small part of the code in the following method was inspired by works of David | |||
# Eberly, Geometric Tools LLC, in code released under the Boost Software | |||
# License (included at the end of this file). | |||
@inline function _eig{T<:Real}(::Size{(3,3)}, A::Base.LinAlg.RealHermSymComplexHerm{T}, permute, scale) | |||
@inline function _eig(::Size{(3,3)}, A::Base.LinAlg.RealHermSymComplexHerm{T}, permute, scale) where {T <: Real} |
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.
Can the where
pieces be removed in this file and replaced with the shorthand?
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.
This one uses T
.
|
So it wasn't just me that saw that? I reloaded and it seems fine now. |
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.
You're a hero.
@pure Size(::SUnitRange{Start, End}) where {Start,End} = Size(End-Start+1) | ||
|
||
@pure @propagate_inbounds function getindex(x::SUnitRange{Start,End}, i::Int) where {Start, End} | ||
@boundscheck if i < Start || i > 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.
So it looks like you've defined a static version of what I'm calling an IdentityRange
or IdempotentRange
, see JuliaArrays/IdentityRanges.jl#1 and JuliaLang/julia#21052. Just to check, you're aware that these are non-1 indices arrays you've defined here? If this is intentional, you should definitely define the indices
function for them.
If that's not what you're intending, you should be checking against 1 <= i <= End - Start + 1
and then return i + Start - 1
.
src/abstractarray.jl
Outdated
end | ||
@inline reshape(a::StaticArray, s::Size) = similar_type(a, s)(Tuple(a)) | ||
@generated function reshape(a::AbstractArray, s::Size{S}) where {S} | ||
if IndexStyle(a) == IndexLinear() # TODO this isn't "hyperpure" |
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.
Can you make this safer by dispatching on the IndexStyle
in "regular" functions?
reshape(a::AbstractArray, s::Size) = _reshape(IndexStyle(a), a, s)
@generated function _reshape(::IndexLinear, a, s::Size{S}) where {S}
...
end
@generated function _reshape(::IndexStyle, a, s::Size{S}) where {S}
...
end
src/abstractarray.jl
Outdated
if IndexStyle(a) == IndexLinear() # TODO this isn't "hyperpure" | ||
exprs = [:(a[$i]) for i = 1:prod(S)] | ||
else | ||
exprs = [:(a[$(inds...)]) for inds ∈ CartesianRange(S)] |
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.
inds.I...
? Also, does this imply that a[4,2]
is defined for a SMatrix{3, 4}
? Or do you mean to be iterating over Size(a)
?
S1, S2 = length(inds1), lengths(inds2) | ||
exprs = [:(m[inds1[$j1], inds2[$j2]]) for j1 = 1:S1, j2 = 1:S2] | ||
return Expr(:call, SMatrix{S1, S2, T}, Expr(:tuple, exprs...)) # I guess SMatrix should be fine? | ||
@propagate_inbounds function getindex(a::StaticArray, inds::Int...) |
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.
Do you really want to support inds::Int...
, or would it be better to support only i::Vararg{Int, N}
where N
matches the dimensionality of the array? If you do that, then you get all the goodness of dropped 1s, etc, for free.
Also, you may not need this at all for IndexStyle(a)::IndexLinear
.
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.
Hmm... yes this seems like a valid point.
I should check if the implementation here is faster than a basic sub2ind
one.
return quote | ||
$(Expr(:meta, :inline, :propagate_inbounds)) | ||
$(Expr(:call, :getindex, :a, Expr(:tuple, inds...))) | ||
@generated function _getindex_scalar(::Size{S}, a::StaticArray, inds::Int...) where S |
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.
If you need this, split this first segment into a sub2ind_expr
function, or something?
ind_types = inds.parameters | ||
current_ind = ones(Int,length(ind_types)) | ||
more = true | ||
while more |
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.
This overall logic seems repeated in many places...is it consolidatable?
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.
That might have been better (but it's already written, so...)
@SimonDanisch - what is the plan for |
See if we can make it work?! ;) I will have to look into it very soon! |
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.
More partial review, got down to the end of mapreduce...
src/linalg.jl
Outdated
end | ||
@inline function _cross(::Size{(3,)}, a::StaticVector{<:Unsigned}, b::StaticVector{<:Unsigned}) | ||
T = typeof(a[2]*b[3]-a[3]*b[2]) | ||
@inbounds return similar_type(a, typeof(Signed(a[2]*b[3])-Signed(a[3]*b[2])))(((Signed(a[2]*b[3])-Signed(a[3]*b[2]), Signed(a[3]*b[1])-Signed(a[1]*b[3]), Signed(a[1]*b[2])-Signed(a[2]*b[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.
T
unused here and above.
I guess someone wanted these Unsigned
versions or they wouldn't be here... but they sure look like an oddity to me, and Base
has no such specialization.
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.
Yeah, it just happens to be needed for the determinant algorithm, and someone raised an issue about that! Seemed a bit silly but oh well.
src/linalg.jl
Outdated
for j = 2:length(a) | ||
expr = :($expr + conj(a[$j]) * b[$j]) | ||
end | ||
@inline dot(a::StaticVector, b::StaticVector) = _dot(same_size(a, b), a, b) |
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.
Could just call _vecdot()
src/linalg.jl
Outdated
expr = :(conj(a[1]) * b[1]) | ||
for j = 2:prod(S) | ||
expr = :($expr + conj(a[$j]) * b[$j]) | ||
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.
Code golf :-)
expr = Expr(:call, :+, [:(conj(a[$j])*b[$j]) for j=1:prod(S)]...)
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.
lol.
Are we sure that multi-argument +
is performant?
src/linalg.jl
Outdated
return zero(real(eltype(a))) | ||
end | ||
|
||
expr = :(real(conj(a[1]) * a[1])) | ||
for j = 2:length(a) | ||
for j = 2:prod(S) | ||
expr = :($expr + real(conj(a[$j]) * a[$j])) |
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.
abs2(x)
is probably better here than real(conj(x)*x)
?
return zero(eltype(a)) | ||
end | ||
|
||
exprs = [:(a[$(sub2ind(s, i, i))]) for i = 1:s[1]] | ||
exprs = [:(a[$(sub2ind(S, i, i))]) for i = 1:S[1]] | ||
total = reduce((ex1, ex2) -> :($ex1 + $ex2), exprs) |
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.
Not really this PR, but it's less Expr allocation/nesting to reduce this as total = Expr(:call, :+, exprs...)
.
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.
That will wreck performance if exprs
is too long because julia can't handle too many function argument well.
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.
Although I have noticed this reduction pattern to be quite tough on inference and thus long compilation times.
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.
Are we sure that multi-argument + is performant? (There will be a splat somewhere, which potentially ruins performance for vectors and matrices with 16+ elements)
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 thought it was solved way back in 0.4 via a hack I spotted in inference.
But I've just done a test and you're right to be worried about this - generated code quality still falls off a cliff with more than 7 arguments to +
. This is despite the fact that +
is force inlined via a hack in inference.
Looking at @code_typed sumit(@SVector(ones(8)))
of
@generated function sumit(v)
s = Expr(:call, :+, [:(v[$i]) for i=1:length(v)]...)
quote
@inbounds s = $s
s
end
end
shows some utterly strange things going on as a function of the SVector
length.
src/linalg.jl
Outdated
@@ -125,60 +79,56 @@ end | |||
@inbounds return $(Expr(:call, newtype, Expr(:tuple, exprs...))) | |||
end | |||
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.
To delete? Will RowVector do the trick instead?
if s === Size(a1) | ||
return _same_size(s, as...) | ||
else | ||
throw(DimensionMismatch("Dimensions must match. Got inputs with $s and $(Size(a1)).")) | ||
end | ||
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.
Neato utility
tmp = [:(a[$j][$i]) for j ∈ 1:length(a)] | ||
exprs[i] = :(f($(tmp...))) | ||
end | ||
eltypes = [eltype(a[j]) for j ∈ 1:length(a)] # presumably, `eltype` is "hyperpure"? |
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.
julia-0.6 with all new hyperpure™ functionality, washing your generated functions even whiter.
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.
lol.
Yes - should I make a PR to Julia NEWS.md highlighting our new hyperpure™ technology stack?
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.
Well, I got to the bottom! Added some more comments on minor niceties, nothing big :-) There's a few things which have been removed and should be documented.
src/matrix_multiply.jl
Outdated
can_mutate = !isbits(A) || !isbits(B) # !isbits implies can get a persistent pointer (to pass to BLAS). Probably will change to !isimmutable in a future version of Julia. | ||
can_blas = T == TA && T == TB && T <: Union{Float64, Float32, Complex{Float64}, Complex{Float32}} | ||
@generated function _A_mul_B(Sa::Size{sa}, Sb::Size{sb}, a::StaticMatrix{Ta}, b::StaticMatrix{Tb}) where {sa, sb, Ta, Tb} | ||
can_mutate = a.mutable && b.mutable # TODO this probably isn't safe. Maybe a trait?? |
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.
This should be fine, shouldn't it? a
and b
are DataType
in the generator context, and even if the field access here was turned into a call to getfield
, it's an intrinsic (I think?) and can't be extended.
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.
It's a bit funny... you can have a StaticArray
struct which is immutable but for which setfield!
works (such as SizedArray
), and you can (in theory) have a mutable struct
and not define setfield!
. Annoying...
I probably should just specialize on Union{SizedMatrix{<:BlasFloat}, MMatrix{<:BlasFloat}}
.
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 good.
src/matrix_multiply.jl
Outdated
@_inline_meta | ||
T = promote_matprod(Ta, Tb) | ||
C = similar(a, T, $S) | ||
A_mul_B_blas!($S, C, Sa, Sb, a, b) |
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.
Nice.
TB = eltype(B) | ||
T = promote_matprod(TA, TB) | ||
|
||
can_blas = T == TA && T == TB && T <: Union{Float64, Float32, Complex{Float64}, Complex{Float32}} |
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.
👍 for less code!
(a[1,2]*a[3,1] - a[1,1]*a[3,2])*b[2] + | ||
(a[1,1]*a[2,2] - a[1,2]*a[2,1])*b[3]) / d ) | ||
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.
It's a huge improvement to move these to traits. Nice!
@pure getindex{S}(::Size{S}, i::Int) = i <= length(S) ? S[i] : 1 | ||
struct Length{L} | ||
function Length{L}() where L | ||
check_length(L) |
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.
Oh, can you use that trick you were showing to avoid the need for check_length
?
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.
Not needed of course, just a nicety.
src/util.jl
Outdated
@@ -28,6 +28,9 @@ end | |||
end | |||
end | |||
|
|||
|
|||
# TODO: the below seems to be type piracy... | |||
#= |
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.
Then let's just delete these, and document it?
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.
Hard to know whether to depwarn them, really they should never have been in here in the first place.
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.
Personally, I'd lean toward just deleting any type piracy, and documenting it in the release notes.
@@ -0,0 +1,7 @@ | |||
@testset "Custom types" begin | |||
# Issue 123 | |||
@eval (struct MyType{N, T} <: StaticVector{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.
You don't need the brackets around struct
, I think?
test/linalg.jl
Outdated
@test_broken @inferred(v1 + v4) === @SVector [6, 7, 8, 9] | ||
@test_broken @inferred(v3 + v2) === @SVector [6, 7, 8, 9] | ||
@test_broken @inferred(v1 - v4) === @SVector [-2, 1, 4, 7] | ||
@test_broken @inferred(v3 - v2) === @SVector [-2, 1, 4, 7] |
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.
Could use a comment discussing what happened here. Same for other newly broken tests, I guess.
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.
ie, obviously there's a decision to be made about whether we reimplement this functionality (in which case we delete the broken tests). Just a one liner about the decision to leave it broken for now, perhaps?
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.
Well... probably a good idea...
OK, I'll make a release to METADATA sometime over the next day or two - anyone who finds a bug before then, I'd appreciate a report. |
Just wanted to mention that ValidatedNumerics's tests pass with this branch on 0.6 -- many thanks for the hard work! |
I'm delighted to report that ImageFiltering passes as well! Thanks so very much! I assume the new release will be called 0.4? |
Yep, to make it official, I just tagged v0.4.0 in github - its up to attobot now :) |
@inbounds return $expr | ||
end | ||
end | ||
@inline function mapreduce(f, op, a::StaticArray...) |
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.
Little odd, but this allows for mapreduce(f, op)
which would normally error. same_size()
isn't defined right now, but it might at some point, by accident or piracy.
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.
This will still error :)
I do see your point (though it seems unlikely that this signature would clash with ones defined by others). Are you requesting that I modify the signature (to tag the release in METADATA)?
same_size()
isn't defined right now, but it might at some point, by accident or piracy.
I'm not quite sure how to respond, since I'm not even exporting this. I do intend to keep watch on new features and breaking changes for Julia 0.7/1.0 (and a new export from Base
would count as more than bugfix w.r.t. semver). But yes, it would be useful to generally have a function like this exported from Base
one day.
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.
Just trying to think of ways in which the 0-occurrences version of this might be a problem (or not). I guess there could also be other packages that might do the same basic signature but for vararg of their own type, in which case mapreduce(f, op)
might be ambiguous between here and that other package? Maybe a little safer to have the signature 1-or-more instead of 0-or-more, but maybe I'm just being paranoid.
@@ -1,2 +1 @@ | |||
julia 0.5 | |||
Compat 0.19.0 |
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.
@compat
is still used in test/fixed_size_arrays.jl
, though it looks like that's now dead code
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, that file is not deleted because I think Simon Danisch will revive it sometime
foreachfield and staticschema cleanup
This was quite a large amount of work. Most of the files have been rewritten, and hopefully code quality has improved a bit. Note these improvements:
broadcast
,broadcast!
,map
andmap!
now support arbitrary many static array inputs.Size
trait for dispatchLength
trait and related pure functions1:n
. (However, this wasn't exported.)We have this breaking change:
similar_type
defaults toSVector
, etc - it does not preserve immutability. This helps e.g. with things likem[i, SVector(1,2,3)]
wherem::Matrix
, and should generally be beneficial for speed.We have this regression
SMatrix * Vector
have been removed. We can add these back in, if they are popular, but until we have inlined non-isbits immutables, we shouldn't do the simple thing here and wrap them in aSizedArray
(well, we could, but it might cost more to allocate a pointer to the heap + gc, than to perform the actual operation).I don't expect a full code review here. Nonetheless I'll leave this PR open for a day or two. (Please feel free to comment here before or after it is merged - we can always improve the code).
Closes #113 #109 #106 #95