-
-
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
Address type stability issues in #12574 and fix a bug or two #12594
Changes from all commits
dd009d6
7465943
4d50e23
095e0c4
1c08f8d
851e7a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,10 +57,53 @@ ctranspose(A::Hermitian) = A | |
trace(A::Hermitian) = real(trace(A.data)) | ||
|
||
#tril/triu | ||
tril(A::Hermitian,k::Integer=0) = tril(A.data,k) | ||
triu(A::Hermitian,k::Integer=0) = triu(A.data,k) | ||
tril(A::Symmetric,k::Integer=0) = tril(A.data,k) | ||
triu(A::Symmetric,k::Integer=0) = triu(A.data,k) | ||
function tril(A::Hermitian, k::Integer=0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It passes tests locally with this change. Do we need to run CI again? |
||
if A.uplo == 'U' && k <= 0 | ||
return tril!(A.data',k) | ||
elseif A.uplo == 'U' && k > 0 | ||
return tril!(A.data',-1) + tril!(triu(A.data),k) | ||
elseif A.uplo == 'L' && k <= 0 | ||
return tril(A.data,k) | ||
else | ||
return tril(A.data,-1) + tril!(triu!(A.data'),k) | ||
end | ||
end | ||
|
||
function tril(A::Symmetric, k::Integer=0) | ||
if A.uplo == 'U' && k <= 0 | ||
return tril!(A.data.',k) | ||
elseif A.uplo == 'U' && k > 0 | ||
return tril!(A.data.',-1) + tril!(triu(A.data),k) | ||
elseif A.uplo == 'L' && k <= 0 | ||
return tril(A.data,k) | ||
else | ||
return tril(A.data,-1) + tril!(triu!(A.data.'),k) | ||
end | ||
end | ||
|
||
function triu(A::Hermitian, k::Integer=0) | ||
if A.uplo == 'U' && k >= 0 | ||
return triu(A.data,k) | ||
elseif A.uplo == 'U' && k < 0 | ||
return triu(A.data,1) + triu!(tril!(A.data'),k) | ||
elseif A.uplo == 'L' && k >= 0 | ||
return triu!(A.data',k) | ||
else | ||
return triu!(A.data',1) + triu!(tril(A.data),k) | ||
end | ||
end | ||
|
||
function triu(A::Symmetric, k::Integer=0) | ||
if A.uplo == 'U' && k >= 0 | ||
return triu(A.data,k) | ||
elseif A.uplo == 'U' && k < 0 | ||
return triu(A.data,1) + triu!(tril!(A.data.'),k) | ||
elseif A.uplo == 'L' && k >= 0 | ||
return triu!(A.data.',k) | ||
else | ||
return triu!(A.data.',1) + triu!(tril(A.data),k) | ||
end | ||
end | ||
|
||
## Matvec | ||
A_mul_B!{T<:BlasFloat,S<:StridedMatrix}(y::StridedVector{T}, A::Symmetric{T,S}, x::StridedVector{T}) = BLAS.symv!(A.uplo, one(T), A.data, x, zero(T), y) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,65 +149,98 @@ istril(A::UnitLowerTriangular) = true | |
istriu(A::UpperTriangular) = true | ||
istriu(A::UnitUpperTriangular) = true | ||
|
||
function tril(A::UpperTriangular,k::Integer=0) | ||
function tril!(A::UpperTriangular,k::Integer=0) | ||
n = size(A,1) | ||
if abs(k) > n | ||
throw(ArgumentError("requested diagonal, $k, out of bounds in matrix of size ($n,$n)")) | ||
elseif k < 0 | ||
return UpperTriangular(zeros(A.data)) | ||
fill!(A.data,0) | ||
return A | ||
elseif k == 0 | ||
return UpperTriangular(diagm(diag(A))) | ||
for j in 1:n, i in 1:j-1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for not suggesting this earlier, but couldn't all of these cases except for the error branch be equivalently stated as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we fix the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's all correct and good to merge now. Making it more concise can be left for later. Someone also needs to fix the sub-vs-superdiagonal thing in the docs but that doesn't have to be done here. I'll do it if no one beats me to it and I don't forget about it. |
||
A.data[i,j] = 0 | ||
end | ||
return A | ||
else | ||
return UpperTriangular(triu(tril(A.data,k))) | ||
return UpperTriangular(tril!(A.data,k)) | ||
end | ||
end | ||
triu!(A::UpperTriangular,k::Integer=0) = UpperTriangular(triu!(A.data,k)) | ||
|
||
triu(A::UpperTriangular,k::Integer=0) = UpperTriangular(triu(triu(A.data),k)) | ||
|
||
function tril(A::UnitUpperTriangular,k::Integer=0) | ||
function tril!(A::UnitUpperTriangular,k::Integer=0) | ||
n = size(A,1) | ||
if abs(k) > n | ||
throw(ArgumentError("requested diagonal, $k, out of bounds in matrix of size ($n,$n)")) | ||
elseif k < 0 | ||
return UnitUpperTriangular(zeros(A.data)) | ||
fill!(A.data,0) | ||
return UpperTriangular(A.data) | ||
elseif k == 0 | ||
return UnitUpperTriangular(eye(A)) | ||
fill!(A.data,0) | ||
for i in diagind(A) | ||
A.data[i] = one(eltype(A)) | ||
end | ||
return UpperTriangular(A.data) | ||
else | ||
return UnitUpperTriangular(triu(tril(A.data,k))) | ||
for i in diagind(A) | ||
A.data[i] = one(eltype(A)) | ||
end | ||
return UpperTriangular(tril!(A.data,k)) | ||
end | ||
end | ||
|
||
triu(A::UnitUpperTriangular,k::Integer=0) = UnitUpperTriangular(triu(triu(A.data),k)) | ||
function triu!(A::UnitUpperTriangular,k::Integer=0) | ||
for i in diagind(A) | ||
A.data[i] = one(eltype(A)) | ||
end | ||
return triu!(UpperTriangular(A.data),k) | ||
end | ||
|
||
function triu(A::LowerTriangular,k::Integer=0) | ||
function triu!(A::LowerTriangular,k::Integer=0) | ||
n = size(A,1) | ||
if abs(k) > n | ||
throw(ArgumentError("requested diagonal, $k, out of bounds in matrix of size ($n,$n)")) | ||
elseif k > 0 | ||
return LowerTriangular(zeros(A.data)) | ||
fill!(A.data,0) | ||
return A | ||
elseif k == 0 | ||
return LowerTriangular(diagm(diag(A))) | ||
for j in 1:n, i in j+1:n | ||
A.data[i,j] = 0 | ||
end | ||
return A | ||
else | ||
return LowerTriangular(tril(triu(A.data,k))) | ||
return LowerTriangular(triu!(A.data,k)) | ||
end | ||
end | ||
|
||
tril(A::LowerTriangular,k::Integer=0) = LowerTriangular(tril(tril(A.data),k)) | ||
tril!(A::LowerTriangular,k::Integer=0) = LowerTriangular(tril!(A.data,k)) | ||
|
||
function triu(A::UnitLowerTriangular,k::Integer=0) | ||
function triu!(A::UnitLowerTriangular,k::Integer=0) | ||
n = size(A,1) | ||
if abs(k) > n | ||
throw(ArgumentError("requested diagonal, $k, out of bounds in matrix of size ($n,$n)")) | ||
elseif k > 0 | ||
return UnitLowerTriangular(zeros(A.data)) | ||
fill!(A.data,0) | ||
return LowerTriangular(A.data) | ||
elseif k == 0 | ||
return UnitLowerTriangular(eye(A)) | ||
fill!(A.data,0) | ||
for i in diagind(A) | ||
A.data[i] = one(eltype(A)) | ||
end | ||
return LowerTriangular(A.data) | ||
else | ||
return UnitLowerTriangular(tril(triu(A.data,k))) | ||
for i in diagind(A) | ||
A.data[i] = one(eltype(A)) | ||
end | ||
return LowerTriangular(triu!(A.data,k)) | ||
end | ||
end | ||
|
||
tril(A::UnitLowerTriangular,k::Integer=0) = UnitLowerTriangular(tril(tril(A.data),k)) | ||
function tril!(A::UnitLowerTriangular,k::Integer=0) | ||
for i in diagind(A) | ||
A.data[i] = one(eltype(A)) | ||
end | ||
return tril!(LowerTriangular(A.data),k) | ||
end | ||
|
||
transpose{T,S}(A::LowerTriangular{T,S}) = UpperTriangular{T, S}(transpose(A.data)) | ||
transpose{T,S}(A::UnitLowerTriangular{T,S}) = UnitUpperTriangular{T, S}(transpose(A.data)) | ||
|
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 could use
fill!
instead of allocating newzeros
arrays, right?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 tested this locally and it works. Will wait for CI to finish then update.
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 this applies throughout for (most of?) the rest of the types too. Anywhere it's possible to make the
!
versions allocation-free and in-place, then I think that would be a good goal. And aim for type-stability but with the smallest amount of type widening that makes sense. The one-arg case could possibly be made to return a more specialized type than the two-arg case for some types since it's more specific in its behavior, but that would require extra methods rather than using default argument values and could be left as a future enhancement.