-
-
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
Added ConjArray
wrapper type for conjugate array views
#20047
Conversation
Follow-up of #19670 |
@propagate_inbounds getindex{T,N}(a::ConjArray{T,N}, i::Int) = conj(getindex(a.parent, i)) | ||
@propagate_inbounds getindex{T,N}(a::ConjArray{T,N}, i::Vararg{Int,N}) = conj(getindex(a.parent, i...)) | ||
@propagate_inbounds setindex!{T,N}(a::ConjArray{T,N}, v, i::Int) = setindex!(a.parent, conj(v), i) | ||
@propagate_inbounds setindex!{T,N}(a::ConjArray{T,N}, v, i::Vararg{Int,N}) = setindex!(a.parent, conj(v), i...) |
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.
Seems like it should pass through a stride(A,k)
and pointer
(and unsafe_convert
to a pointer) call to the underlying array. (Similarly for RowVector
.)
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, not pointer
since the underlying data is not conjugated. But we should provide pointer
for RowVector
. And we should still provide stride
for ConjArray
(this is potentially useful for telling you what direction to traverse an array).
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, I was hoping to address all the StridedArray
behavior at some point...
(it is a bit annoying that it is a type not a trait)
parent::A | ||
end | ||
|
||
@inline ConjArray{T,N}(a::AbstractArray{T,N}) = ConjArray{conj_type(T), N, typeof(a)}(a) |
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.
We should probably have a similar
function that calls similar(parent)
.
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.
Agreed
base/linalg/conjarray.jl
Outdated
@inline _conj(a::AbstractArray) = ConjArray(a) | ||
@inline _conj{T<:Real}(a::AbstractArray{T}) = a | ||
@inline _conj(a::ConjArray) = parent(a) | ||
@inline _conj{T<:Real}(a::ConjArray{T}) = parent(a) |
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.
Don't think this method is needed?
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.
In functionality, you are right, but this is a ambiguity resolution of the two methods above (not that ConjArray{T} where T<:Real
is common, but it is possible for a user to create one, unless you prefer for the constructor to throw in that case?)
Should't there be some more specialized linear-algebra operations? e.g. |
NEWS.md
Outdated
@@ -185,6 +185,10 @@ Library improvements | |||
|
|||
* `notify` now returns a count of tasks woken up ([#19841]). | |||
|
|||
* Introduced a wrapper type for lazy complex conjugation of arrays, `ConjArray`. | |||
Currently, it is used by default for the new `RowVector` type only, and | |||
enforces that both `transpose(vec)` and `ctranspose(vec)` are views not copies. |
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.
copies.
-> copies ([#20047]).
72ca30a
to
b70aa6e
Compare
test/sparse/sparse.jl
Outdated
# @test which(\, (SparseMatrixCSC, AbstractVecOrMat)).module == Base.SparseArrays | ||
#end | ||
@testset "issue #16548" begin | ||
@test_broken which(\, (SparseMatrixCSC, AbstractVecOrMat)).module == Base.SparseArrays |
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 replaced with a test that serves the same purpose, if possible, cc @Sacha0
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 agree. I haven't been able to think of an elegant way of doing the same check.
Does anyone know the status/purpose of the "\
revisions"?
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.
Status of \
revisions: Chances are no one has worked on improving the mechanism further since #16548 (particularly given that improving that mechanism depends on compiler improvements, see #16979 (comment)).
Had a brief look at fixing this test. A simple fix would be to retrieve the method matches for \
with (SparseMatrixCSC, AbstractVecOrMat)
arguments and check that all such methods live in the SparseArrays
module. For example, something along the lines of all(meth -> meth.module == Base.SparseArrays, methods(\, (SparseMatrixCSC, AbstractVecOrMat)).ms)
could do the trick. Thoughts? Best!
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, OK. At first I thought the issue might have been it going through a rowvector.jl
method first before going to the Sparse
module, but in fact this may be a disambiguity method that I added to Sparse
, so that should work.
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.
a disambiguity method that I added to Sparse
Correct. That there are now two matching methods rather than one is what caused the existing test to fail:
julia> which(\, (SparseMatrixCSC, AbstractVecOrMat))
ERROR: method match is ambiguous for the specified argument types
Stacktrace:
[1] which(::Any, ::Any) at ./reflection.jl:715
julia> methods(\, (SparseMatrixCSC, AbstractVecOrMat))
# 2 methods for generic function "\":
\(::SparseMatrixCSC, ::RowVector) in Base.SparseArrays at sparse/linalg.jl:875
\(A::SparseMatrixCSC, B::Union{AbstractArray{T,1},AbstractArray{T,2}} where T) in Base.SparseArrays at sparse/linalg.jl:855
Best!
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 fixed this for now, but I'm guessing that this will need to change again with TransposedMatrix
(the thing it is testing may not even be true after that...).
I think this is done now.
Hmm... I thought that getting rid of the EDIT: I believe |
A question: what should The goal here was to make both EDIT: actually making a copy would mean it's trivial that the BLAS routines get used in |
IIRC, the last time I looked Julia was as fast as BLAS for 1d operations (and indeed faster for small objects because of inlining, which is not possible with BLAS). There may have been some regression in our SIMD capabilities, so that may not be so true anymore, but I'd rather see this implemented in Julia code and then work on our SIMD. |
test/linalg/conjarray.jl
Outdated
@@ -0,0 +1,23 @@ | |||
# This file is a part of Julia. License is MIT: http://julialang.org/license | |||
|
|||
@testset "RowVector" begin |
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.
don't think this outer testset is necessary, the test system inserts a test set around each file anyway
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, thanks for the heads-up. The behavior of Base tests is quite different to what happens with packages, but I had seen an issue (from memory) about using @testset
more so I used my usual style and hoped things would be picked up.
(is the hope to unify the package and base approaches in the future?)
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.
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.
Very cool!
There are the BLAS3 cases of |
For example, it would be good to have
use BLAS if Oh, wait, I forgot that we don't have |
Right, the next step is a much more disruptive (in terms of code) PR that introduces Because of the combinatorial explosion of methods of having all the I'm guessing this is post v0.6 (primarily for the reason is that we've already run out of time) unless people really think it's worth pursuing now. |
bf7ebdb
to
3de51ef
Compare
OK I've done a little bit more work on this and rebased... just the sparse module |
base/linalg/rowvector.jl
Outdated
@inline similar(rowvec::RowVector) = RowVector(similar(parent(rowvec))) | ||
@inline similar{T}(rowvec::RowVector, ::Type{T}) = RowVector(similar(parent(rowvec), transpose_type(T))) | ||
|
||
# Resizing similar currently looses its RowVector property. |
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.
loses
1d41284
to
9e0e1cf
Compare
OK, I fixed the broken test (upgraded from "brittle" to "somewhat brittle") and typo, and have rebased. Regarding the To me, this had felt like work that could be done along with |
@inline ctranspose{T<:Real}(vec::AbstractVector{T}) = RowVector(vec) | ||
|
||
@inline transpose(rowvec::RowVector) = rowvec.vec | ||
@inline transpose(rowvec::ConjRowVector) = copy(rowvec.vec) # remove the ConjArray wrapper from any raw vector |
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.
Why does this make a copy?
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 logic was to make sure that vectors are always unwrapped, so that calls to BLAS are generally used. This is partly because the PR doesn't create a bunch of new methods for *(conjarray, array)
, etc. We also have "view semantic" for row vectors and "copy semantic" for vectors, which seemed more consistent than views for vectors and rowvectors and copies for everything else.
(That is, from the user's perspective, only the new RowVector
type gets the view semantic, conjugated or not. The old types behave as before, so hopefully this is more backward compatible. Ideally these changes would have been made at the same time as TransposedMatrix
to make all of this more consistent...)
Of course I open to doing it the other way, if people thing that makes more sense.
@@ -147,6 +154,11 @@ end | |||
|
|||
# Multiplication # | |||
|
|||
# inner product -> dot product specializations | |||
@inline *{T<:Real}(rowvec::RowVector{T}, vec::AbstractVector{T}) = dot(parent(rowvec), vec) | |||
@inline *(rowvec::ConjRowVector, vec::AbstractVector) = dot(rowvec', vec) |
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 worried about potential performance regressions if we don't also have *(rowvec,Matrix) = At_mul_B
and *(conjrowvec,Matrix) = Ac_mul_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.
The first is true, but not the way you think: you end up on this line so you get *(rowvec, matrix) = RowVector(At_mul_B(matrix, parent(rowvec)))
. Would that be a performance penalty?
I should chase down all the conjugated cases and make sure they do something sensible. I think what happens is a conjugated copy of the parent vector is created as a temporary, and the above gets called. (We should be able to remove this temporary - one way would have the output become a ConjRowVector
which seems a little unusual).
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.
RowVector(At_mul_B(matrix, parent(rowvec)))
should be fine.
What do we need to do to make forward progress here? |
|
We can't have |
test/linalg/conjarray.jl
Outdated
end | ||
|
||
@testset "RowVector conjugates" begin | ||
v = [1+im, 1-im] |
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.
4-space
9e0e1cf
to
a1b2763
Compare
Rebased, indentation fixed. (If you want to merge this now before "alpha" then we can look at any remaining |
Bump |
I like it. If edit: I also wish nanosoldier were working on master right now |
Thanks. I'm already toying with
Right. On one hand, I'm definitely already using it in my toying around, but it is one more symbol in the namespace. I kind-of felt having the vector and array forms and not the matrix form as being a bit odd and distinct to how these things typically come in triples. I'm easy. |
LGTM. I'd still like a method to improve performance in |
base/linalg/conjarray.jl
Outdated
A lazy-view wrapper of an `AbstractArray`, taking the elementwise complex | ||
conjugate. This type is usually constructed (and unwrapped) via the `conj()` | ||
function (or related `ctranspose()`), but currently this is the default behavior | ||
for `RowVector` only. |
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.
Perhaps a doctest here with an example of behaviour?
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'll have to learn what a doctest is, first. I guess I'll try the docs.
base/linalg/rowvector.jl
Outdated
""" | ||
conj(rowvector) | ||
|
||
Returns a `ConjArray` lazy view of the input, where each element is conjugated. |
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.
Perhaps a @ref
to ConjArray
and maybe a doctest?
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 didn't know about @ref
either, but that seems useful.
Done, @KristofferC . I had trouble getting either of
to work, though, but perhaps this is good enough. |
I think this might be good to go? |
24cce76
to
ced2ca2
Compare
Looks like the tests need to be updated after #20423. |
Bump. This is one of the last remaining feature changes for 0.6. |
@StefanKarpinski waiting on CI, but this should be good to merge now. |
test/linalg/rowvector.jl
Outdated
@@ -237,19 +235,3 @@ end | |||
|
|||
@test_throws DimensionMismatch ut\rv | |||
end | |||
|
|||
# issue #20389 | |||
@testset "1 row/col vec*mat" begin |
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.
shouldn't delete these
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
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 think one of the rebases must have done something odd here. I'll fix 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.
fixed
5367225
to
640e7de
Compare
By default, this is used only in conjugation with `RowVector`, so that both `transpose(vec)` and `ctranspose(vec)` both return views.
640e7de
to
db90a8e
Compare
Squashed and rebased, for convenience. |
So the pending work here is all adding optimized internal methods, right? |
That's correct, Stefan. It shouldn't affect the user interface or behaviour. |
Great – let's pull the trigger once CI passes everywhere. |
Looks like Travis finally started. BTW, Stefan, I have started on a branch here with |
# a "view" for conj(::AbstractArray) | ||
@inline conj(rowvec::RowVector) = RowVector(conj(rowvec.vec)) | ||
""" | ||
conj(rowvector) |
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 worth going through CI again right now, but this should probably say conj(v::RowVector)
to be specific?
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 took the liberty of changing this over #20446
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.
@tkelman are we moving towards these more accurate type signatures in docs? I was copying the style that I've seen in a lot of other places, but for myself I would have more naturally written it like you have 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.
if the docstring description applies generally, then the signature should be general. if it's about a method for a specific type, then the signature should show 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.
thanks
By default, this is used only in conjugation with
RowVector
, so that bothtranspose(vec)
andctranspose(vec)
both return views.However, this will pave the way for views for transposed matrices and replacement of
Ac_mul_B
, etc by specialized methods on*
, simplifying parsing.