|
1 | 1 | # Inputs |
2 | 2 | # ------ |
3 | | -function copy_input(::typeof(power), A::AbstractMatrix, p::Real) |
4 | | - return copy!(similar(A, float(eltype(A))), A), p |
5 | | -end |
6 | | -copy_input(::typeof(power), A::Diagonal, p::Real) = map_diagonal(float, A), p |
| 3 | +copy_input(::typeof(power), A::AbstractMatrix, p::Real) = _matrixfunction_copy_input(A), p |
7 | 4 |
|
8 | 5 | function check_input(::typeof(power!), A::AbstractMatrix, p::Real, powA, alg::AbstractAlgorithm) |
9 | | - m = LinearAlgebra.checksquare(A) |
10 | | - @check_size(powA, (m, m)) |
11 | | - @check_scalar(powA, A) |
12 | | - return nothing |
13 | | -end |
14 | | - |
15 | | -function check_input(::typeof(power!), A::AbstractMatrix, p::Real, powA, ::DiagonalAlgorithm) |
16 | | - m = LinearAlgebra.checksquare(A) |
17 | | - @assert isdiag(A) |
18 | | - @assert powA isa Diagonal |
19 | | - @check_size(powA, (m, m)) |
20 | | - @check_scalar(powA, A) |
21 | | - return nothing |
| 6 | + return _matrixfunction_check_input(A, powA, alg) |
22 | 7 | end |
23 | 8 |
|
24 | 9 | # Algorithm selection |
@@ -60,32 +45,20 @@ function power!(A::AbstractMatrix, p::Real, powA, alg::MatrixFunctionViaEigh) |
60 | 45 | isone(p) && ((powA === A || copy!(powA, A)); return powA) |
61 | 46 | D, V = eigh_full!(A, alg.eigh_alg) |
62 | 47 | diag_alg = DiagonalAlgorithm(; domain_atol = alg.domain_atol) |
63 | | - if isinteger(p) |
64 | | - VD = V * power!(D, p, D, diag_alg) |
65 | | - mul!(powA, VD, V') |
66 | | - return project_hermitian!(powA) |
67 | | - else |
68 | | - # `A^p = (V * D^(p/2)) * (V * D^(p/2))'` is hermitian by construction |
69 | | - Vs = rmul!(V, power!(D, p / 2, D, diag_alg)) |
70 | | - return _mul_herm!(powA, Vs) |
71 | | - end |
| 48 | + isinteger(p) && return _apply_eigh!(powA, V, power!(D, p, D, diag_alg)) |
| 49 | + # `A^p = (V * D^(p/2)) * (V * D^(p/2))'` is hermitian by construction |
| 50 | + return _mul_herm!(powA, rmul!(V, power!(D, p / 2, D, diag_alg))) |
72 | 51 | end |
73 | 52 |
|
74 | 53 | function power!(A::AbstractMatrix, p::Real, powA, alg::MatrixFunctionViaEig) |
75 | 54 | check_input(power!, A, p, powA, alg) |
76 | 55 | iszero(p) && return one!(powA) |
77 | 56 | isone(p) && ((powA === A || copy!(powA, A)); return powA) |
78 | 57 | D, V = eig_full!(A, alg.eig_alg) |
| 58 | + # only a fractional power of a real matrix needs the spectrum off the negative real axis |
| 59 | + eltype(A) <: Real && !isinteger(p) && _clamp_domain_eigenvalues!(D, alg.domain_atol) |
79 | 60 | diag_alg = DiagonalAlgorithm(; domain_atol = alg.domain_atol) |
80 | | - if eltype(A) <: Real |
81 | | - isinteger(p) || _clamp_domain_eigenvalues!(D, alg.domain_atol) |
82 | | - VpD = V * power!(D, p, D, diag_alg) |
83 | | - powAc = rdiv!(VpD, LinearAlgebra.lu!(V)) |
84 | | - return powA .= real.(powAc) |
85 | | - else |
86 | | - powA .= V .* transpose(diagview(power!(D, p, D, diag_alg))) |
87 | | - return rdiv!(powA, LinearAlgebra.lu!(V)) |
88 | | - end |
| 61 | + return _apply_eig!(powA, V, power!(D, p, D, diag_alg)) |
89 | 62 | end |
90 | 63 |
|
91 | 64 | # Diagonal logic |
|
0 commit comments