-
-
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
Handle large integer exponents in matrix powers #55431
base: master
Are you sure you want to change the base?
Changes from all commits
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 | ||||
---|---|---|---|---|---|---|
|
@@ -514,12 +514,38 @@ function (^)(A::AbstractMatrix{T}, p::Integer) where T<:Integer | |||||
end | ||||||
function integerpow(A::AbstractMatrix{T}, p) where T | ||||||
TT = promote_op(^, T, typeof(p)) | ||||||
return (TT == T ? A : convert(AbstractMatrix{TT}, A))^Integer(p) | ||||||
ATT = TT == T ? A : convert(AbstractMatrix{TT}, A) | ||||||
return _integerpow(ATT, p) | ||||||
end | ||||||
_integerpow(A::AbstractMatrix, p) = A^Integer(p) | ||||||
function _integerpow(A::AbstractMatrix, p::Union{Float32, Float64}) | ||||||
# For these exponent types, not all values may be converted to Int | ||||||
# We split the exponentiation into parts for which the exponent can be converted to an Int | ||||||
if p < 0 | ||||||
return _integerpow(inv(A), -p) | ||||||
end | ||||||
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. perhaps explicitly adding a case for 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 this is handled by 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. hmm ok fair |
||||||
m = typemax(Int) | ||||||
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.
Suggested change
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 that the correct value here is 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 you're right that it needs to be |
||||||
if p <= m | ||||||
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. The flow of all of this seems a little more complicated than necessary (maybe I'm wrong). What about just computing |
||||||
return A^Int(p) | ||||||
end | ||||||
# for large numbers, we express A^p as A^(m*q + r) == (A^m)^q * A^r | ||||||
# Here, m may be safely represented as an Int, | ||||||
# and we raise to the power of q by carrying out the decomposition recursively | ||||||
A2 = A^Int(m) | ||||||
q, r = divrem(p, m) | ||||||
if q > 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. nit: this one can directly 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. But the |
||||||
A2 = integerpow(A2, q) | ||||||
end | ||||||
if !iszero(r) | ||||||
A2 *= A^Int(r) | ||||||
end | ||||||
return A2 | ||||||
end | ||||||
|
||||||
function schurpow(A::AbstractMatrix, p) | ||||||
if istriu(A) | ||||||
# Integer part | ||||||
retmat = A ^ floor(Integer, p) | ||||||
retmat = integerpow(A, floor(p)) | ||||||
# Real part | ||||||
if p - floor(p) == 0.5 | ||||||
# special case: A^0.5 === sqrt(A) | ||||||
|
@@ -530,7 +556,7 @@ function schurpow(A::AbstractMatrix, p) | |||||
else | ||||||
S,Q,d = Schur{Complex}(schur(A)) | ||||||
# Integer part | ||||||
R = S ^ floor(Integer, p) | ||||||
R = integerpow(S, floor(p)) | ||||||
# Real part | ||||||
if p - floor(p) == 0.5 | ||||||
# special case: A^0.5 === sqrt(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.
It seems that the long definition here is the more general? Apart from
Float16
(although even there the overhead should be tiny), I'd feel safer with generic types avoiding the assumed-validInteger
conversion since that's how we got here in the first place.EDIT: probably my proposed
_integerpow(A::AbstractMatrix, p::Integer)
is redundant altogether, if not directly overwriting another definition. I haven't traced the whole dispatch logic here.