-
-
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
Add matrix symmetrizing functions #31836
Conversation
A complex |
I think we should stretch the terminology a bit here and have a flag in the |
Can we call this |
That was my first instinct but we already have such a function, it just isn't exported.
|
Okay, can we rename that internal function then? We use |
We'd need to do a PkgEval run to determine whether it's being used, as that has the potential to be breaking. |
Looking at it more, it would be kind of weird to change the internal one, as it's named in keeping with the convention of lowercase/uppercase symmetry. That is, |
shouldn't these function then be returning |
IMO no, because it doesn't make sense for |
I don't agree. E.g. |
I made the change locally but it looks like the
As it stands, |
Can we just call it (In hindsight, I wish we'd just gotten rid of |
I'd be fine with that. Would |
👍 on always returning a |
Heh, turns out that one exists too. Like
|
Bump. We can't call it |
I'd be fine with not returning a wrapper, espcially given the in-place function argument above. Not sure what to do the about the |
Bump. Any interest in this or should it be closed? |
Since I'm not a huge fan of the name We could call it |
Doesn't appear to be. Here's a good approximation of all of the uses in LinearAlgebra plus registered packages: https://juliahub.com/ui/Code?q=%5Cbhermitian%5C%28&w=true&r=true. Only MutableArithmetics seems to be using the one from LinearAlgebra; LinearOperators is defining its own to mean something different, which it exports. |
This looks useful. Can it be rebased? Added triage label to hopefully give it some attention and so we can decide on names and whether to add. |
inds = axes(X, 1) | ||
inds == axes(X, 2) || throw(DimensionMismatch("matrix is not square")) | ||
r = first(inds) | ||
s = step(inds) |
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 it possible to have s != 1
? a[begin:end]
only works if the step is 1, so I thought we required consecutive ranges of indices.
This could be keyword argument: |
The keyword is fine, but that implementation seems suboptimal. You would be running over the data (which is already not very cache friendly due to the fact that you need A[i,j] and A[j,i] at the same time) a second time. I checked the overhead of immediately putting the result in A[j,i] as well. For smaller matrices (100 x 100) the overhead is actually quite significant (contrary to my expectations), but for larger matrices, it goes down. |
Co-authored-by: Alex Arslan <ararslan@comcast.net>
Co-authored-by: Steven G. Johnson <stevenj@alum.mit.edu>
hermitianpart!(A::AbstractMatrix, uplo::Symbol=:U) = Hermitian(_hermitianpart!(A), uplo) | ||
|
||
_hermitianpart(A::AbstractMatrix) = _hermitianpart!(copy_similar(A, Base.promote_op(/, eltype(A), Int))) | ||
_hermitianpart(a::T) where {T<:Number} = convert(Base.promote_op(/, T, Int), real(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.
_hermitianpart(a::T) where {T<:Number} = convert(Base.promote_op(/, T, Int), real(a)) | |
_hermitianpart(a::Number) = real(a) |
As far as I can tell there is no reason to do a conversion 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.
I suggested doing so to ensure that typeof(hermitianpart(x)) == eltype(hermitianpart([x;;]))
for x::Number
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.
When this is used along the diagonal of the matrix, then that conversion happens anyway, since the target array has that specific eltype
. In that case, the diagonal would be filled with complex numbers with vanishing real part, not with real numbers! Ananlogously, computing (a+a') == (a+conj(a))/2
for complex a
yields a complex number, in contrast to real(a)
. OTOH, there is the "operator real part" interpretation, which would perfectly allow the pure real(a)
implementation. I believe, however, that we should remove the hermitianpart(a::Number)
method, because it is (a) currently undocumented, and (b) never called internally (we call _hermitianpart
instead).
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 removed hermitianpart(::Number)
and the type conversion altogether, because the goal is to provide a "matrix symmetrizing function". hermitianpart(::Number)
does not interfere with that goal, so can be an independent PR if necessary. People may then also have a concrete use case and expectations regarding the return type. It would also require an explicit comment in the docstring on how hermitianpart
is working on Number
s.
Co-authored-by: Steven G. Johnson <stevenj@alum.mit.edu>
Ready to go? |
Would there be any appetite for a PR adding the analogue |
This adds functions
symmetrize
andsymmetrize!
, which produce symmetric matrices based on the inputX
via efficient computation of(X + X') / 2
.Benchmark comparison with a naive implementation:
Currently this only deals with real matrices. I can add complex as well if that'd be useful (assuming this is something we want in general).