-
-
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
Overload UniformScaling to make I(n) create a Diagonal matrix. #30298
Conversation
This is... interesting. I’m not sure I love punning on call like this (though I admit toying with the idea from time to time, I generally find it to be the wrong solution...).
That issue isn’t a bug... ;) |
Should this be |
It's just to automatically close the issue but you probably knew that. See "fixed" issue for the discussion.
I think
But in any case, I'll suggest that we postpone the decision regarding |
⋅ ⋅ 0.7 | ||
``` | ||
""" | ||
(J::UniformScaling)(n::Integer) = Diagonal(fill(J.λ, n)) |
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 tempting to use something O(1) sized that acts like a vector filled with a single value here. That would make 5I(n)
just as efficient as (5I)(n)
which, with this implementation are different efficiencies. I was trying to figure out which type in the sea of range types would be the right one but couldn'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.
StepRangeLen(J.λ, 0, n)
, but probably a step too cute.
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.
StepRangeLen
carries redundant data.
There is
using FillArrays
(J::UniformScaling)(n::Integer) = Diagonal(Fill(J.λ, n))
This carries redundant data, too. typeof(1I(3))
is Diagonal{Int64,Fill{Int64,1,Tuple{Base.OneTo{Int64}}}}
.
And the big pile of right brackets is kinda scary.
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 don't have FillArrays in the stdlib.
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 was thinking more long term. Of course an implementation with Eye
can't go in v1.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.
Why not? We can add new features in minor releases. Not sure if we should, but we can.
1.1 branch date approaching: Dec. 6
It seems to me that using FillArrays would involve committing at the last minute to substantially more new design than the current PR. That's why I conflated "should" with "can".
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.
Ah yes, timing-wise 1.1 is too soon. I thought you were saying in terms of compatibility.
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 expect that I(n)
will mostly be used in places where performance isn't critical so I'm not sure it's worth being too cute here to avoid the extra allocations. Sure, if we had the functionality of FillArrays
available then we should use it here but maybe this application isn't sufficient motivation to migrate the functionality to 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.
-
My prediction is one can't predict when dense, dense diagonal, or purely structural1 will be convenient or efficient. Offer a few discoverable options and let the market decide. FillArrays already has
typeof(copy(Eye(n))) == Diagonal{Float64,Array{Float64,1}}
andtypeof(Array(Eye(n))) == Array{Float64,2}
. (I don't know if there are alternatives toFillArrays
) -
If
Eye(n)
is reliable (i.e. works as a dropin replacement for all the code that useseye
), then recommendinguse FillArrays
andEye(n)
doesn't seem overly burdensome. -
In order to investigate use patterns and efficiency and the question in (2) above (but mainly to test a related PR): I tried representing identity matrices with each of 1)
Eye
(Diagonal{Float64,Ones{Float64,1,Tuple{Base.OneTo{Int64}}}}
), 2)Diagonal{Float64,Array{Float64,1}}
, and 3)Array{Float64,2}
in an existing package. The result for the test suite (with it's choice of sizes, types, etc.) is thatArray{Float64,2}
is fastest, both for jit and execution. This includes allocating every timeeye
is used. IIRC the time changes by about a factor of two. Maybe it's not too important for most code. I guess some of the gaps in performance will be closed. But, the ability to do linear indexing on small matrices that stay in cache might be hard to beat. -
this application isn't sufficient motivation to migrate the functionality to base
I agree 100%
1 "dense", "allocated", "packed"? None are precise.
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.
New matrix multiplication API may need the O(1) version of I(n)
. See: https://github.com/JuliaLang/julia/issues/23919#issuecomment-447216076
I still feel a slight concern on having an object that is both a container and a "callable". There are some functions where a positional argument might either be a function to be called or a container to use (e.g. @ararslan is on a roll with #30323, #30328, etc - and this seems to be a recurring pattern). My concern is at some point for one or more of these methods it might become ambiguous whether an input argument of Apart from that,
Sorry @andreasnoack - I merely was amused you didn't use "resolves" or "closes" - https://help.github.com/articles/closing-issues-using-keywords/ 😄 |
@andyferris Your concern here was mentioned in JuliaLang/LinearAlgebra.jl#454. I don't think it will be much of an issue in practice but I can't offer much more than my gut feeling. Allowing |
I just want to mention that having I(n) return bools is counter intuitive wrt zeros(n, n) for instance. It feels like exposing an implementation detail (bool are the lowest common denominator that works for multiplication, but not usually what you want in linear algebra). Of course it's the only sensible choice given how UniformScaling is implemented, but still. From what I can see, the point of having a way to create simply identity matrices is as a starting point to modify them afterwards, or for teaching purposes. Having it be non mutable boolean seems to me likely to be more confusing than anything. |
Related to this, should we change the display of The type information is still printed at the top, the display is more compact, it is more intuitive for algebraic uses, and reflects the fact that |
I think we should at least try this on master and see how it is for a while. It's easy to revert if we don't like it after a while. People who think they'll hate it may be surprised (or people who think they'll like it may also be surprised and hate it). |
@@ -48,6 +48,31 @@ julia> [1 2im 3; 1im 2 3] * I | |||
""" | |||
const I = UniformScaling(true) | |||
|
|||
""" | |||
(J::UniformScaling)(n::Integer) |
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.
Should be I
instead of J
?
Seems ok to me --- if we do this now we get the maximum amount of time to experiment before releasing it in 1.2. |
I also really like the idea of printing Bools as 1 and 0 when possible; much easier to read. |
Triage seems to be on board with this—let's go for it. |
Yes, I'm in favor here, too, especially with the time for experimentation. I'll be curious if folks will generally be satisfied with a |
Now that #30575 is merged, I think it would be good to merge this I'd also be in favor of a future PR extending |
NEWS.md
Outdated
* `mul!`, `rmul!` and `lmul!` methods for `UniformScaling` ([#29506]). | ||
* `Symmetric` and `Hermitian` matrices now preserve the wrapper when scaled with a number ([#29469]). | ||
* Exponentiation operator `^` now supports raising a `Irrational` to an `AbstractMatrix` power ([#29782]). | ||
* `UniformScaling` instances are now callable such that e.g. `I(3)` will produce a `Diagonal` matrix ([#30298]). |
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 changes to NEWS unrelated?
Bump, @andreasnoack: what's up with the NEWS changes? Merge artifact? |
Yes that must have happened during a rebasing. I'll fix it tomorrow. |
I fixed it up on GitHub. If this passes CI, please squash-merge. |
Fixes JuliaLang/LinearAlgebra.jl#454