-
-
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 some (matrix) functions for UniformScaling #28872
Conversation
tests not yet written
This is great — welcome! The failures look to be due to missing imports (or |
In fact none of other matrices in LinearAlgebra specializes cbrt(), I saw sqrt() and then added cbrt() as well without ever thinking.
changes: M = ... to: M(x) = ... in order to make such conversion reusable in following tests
I forgot it...
I'm having trouble understanding julia/stdlib/LinearAlgebra/src/uniformscaling.jl Lines 175 to 178 in 16dcabe
IIUC, line 175-176 is redundant, since |
My guess is that they are there to avoid ambiguities. You can try to comment them out and see what happens. |
I made v a scalar, forgive me
`Union{Bidiagonal,AbstractTriangular} \ UniformScaling` seems redundant because there's another method `AbstractMatrix \ UniformScaling`
Just did a |
also made `isapprox` a standalone testset, because it's irrelevant to `istriu`, `issymmetric`, etc
Hi ZeppLu. It's great that you are working on this. However, it would be great if you could push your changes a little less frequently since each time you push changes, it triggers new CI runs. |
This is my first time working with a CI, apologize for any troubles I've made and thanks for your advice! |
Looks good! Maybe you could also add |
Adding BTW, I'm going to be quite busy this month (Sep), and will be back here as soon as I'm free again. |
*(J1::UniformScaling, J2::UniformScaling) = UniformScaling(J1.λ*J2.λ) | ||
*(B::BitArray{2}, J::UniformScaling) = *(Array(B), J::UniformScaling) | ||
*(J::UniformScaling, B::BitArray{2}) = *(J::UniformScaling, Array(B)) | ||
*(A::AbstractMatrix, J::UniformScaling) = A*J.λ | ||
*(A::AbstractVecOrMat, J::UniformScaling) = 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.
I don't think this is well-defined for vectors. If we think of J being the λ-fold of the identity matrix, the multiplying a vertical vector from the left is meaningless.
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 my linear algebra class was not taught in English, I can't get what "the λ-fold of the identity matrix" means, could you explain it in detail?
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 just saying that it's some identity matrix multiplied by λ.
This operation, multiplying a vec*mat
is frequently an error. I typically think of an identity matrix as being larger than 1x1, so I initially agreed. But this is well-defined if J is considered to be 1x1... and we do say it automatically infers its size based upon the operation at hand.
I do think some extra consideration is still needed here, though, as multiplying rand(5) * fill(2, 1, 1)
yields a 5×1 matrix and not a 5-element vector (as it would return as it's currently defined).
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, the issue is the distinction between a simple vector v
and the linear map x \mapsto v*x
. In the first case, v
should be a vector as we know it. In the second, v
should be an nx1 matrix. Take your example rand(5) * fill(2, 1, 1)
. As it stands, it is non-sensical. Checking with @which
what is actually done leads to
julia/stdlib/LinearAlgebra/src/matmul.jl
Line 62 in d60503a
(*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B |
You see, to perform the product you first need to reshape the vector into a matrix, and only then multiplication works as expected. This and the lines above the quote are somewhat strange "convenience" functions, I would say. Anyway, if we wanted to be consistent with what we already have, we should have
*(A::AbstractMatrix, J::UniformScaling) = A*J.λ
*(a::AbstractVector, J::UniformScaling) = reshape(a*J.λ, length(a), 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.
You'll probably enjoy the discussion in #4774 if you've not discovered that one yet. In short, we've decided to allow vectors to participate in the linear algebra of matrices — and in many cases that means they behave as though they have an implicit trailing ×1
dimension. This particular case is covered in #20423. Sure it's implemented as a reshape, but the important part is the behavior — and this is the behavior we've decided to have.
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 @mbauman, for the link. I remember reading it some long time ago. I agree it's a design decision, and I imagined that behavior is desired. Would
*(a::AbstractVector, J::UniformScaling) = reshape(a, length(a), 1) * J
be then more appropriate? We would leave the multiplication handling to more generic parts of the 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.
Thanks you two! I also consider *(a::AbstractVector, J::UniformScaling) = reshape(a, length(a), 1) * J
more reasonable
*(J::UniformScaling, A::AbstractVecOrMat) = J.λ*A | ||
*(x::Number, J::UniformScaling) = UniformScaling(x*J.λ) | ||
*(J::UniformScaling, x::Number) = UniformScaling(J.λ*x) | ||
|
||
/(J1::UniformScaling, J2::UniformScaling) = J2.λ == 0 ? throw(SingularException(1)) : UniformScaling(J1.λ/J2.λ) | ||
/(J::UniformScaling, A::AbstractMatrix) = lmul!(J.λ, inv(A)) | ||
/(A::AbstractMatrix, J::UniformScaling) = J.λ == 0 ? throw(SingularException(1)) : A/J.λ | ||
/(A::AbstractVecOrMat, J::UniformScaling) = J.λ == 0 ? throw(SingularException(1)) : 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.
I think this should remain AbstractMatrix
for the same reason as above.
@@ -79,11 +81,15 @@ istril(::UniformScaling) = true | |||
issymmetric(::UniformScaling) = true | |||
ishermitian(J::UniformScaling) = isreal(J.λ) | |||
|
|||
isposdef(J::UniformScaling) = isreal(J.λ) && J.λ > 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.
How about
isposdef(J::UniformScaling) = isposdef(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.
you're right!
- *(v::AbstractVector, J::UniformScaling) - /(v::AbstractVector, J::UniformScaling) - isposdef(J::UniformScaling)
hey @ZeppLu, thanks for doing this, any chance you could finish it off? |
also, could this fix the broadcasting with |
Anyone care to take a quick look? @jagot @JeffreySarnoff ? |
I think it looks fine! |
This introduced some build issues:
|
Sorry! Fix in #34819. |
Co-authored-by: Daniel Karrasch <Daniel.Karrasch@gmx.de>
Co-authored-by: Daniel Karrasch <Daniel.Karrasch@gmx.de>
Notations used here:
Methods list:
x .\ I
I ^ x, I .^ x
exp, log, (a)sin/cos/tan/csc/sec/cot(h)
sqrt
v * I, v / I
real, imag
isposdef
tr
wheniszero(J.λ)
BroadcastStyle
?):real, imag, abs, abs2, angle, conj, sqrt, cbrt, ...
float, complex, big, rationalize, ...
and other casting functions