• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.04
/stdlib/LinearAlgebra/src/triangular.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## Triangular
4

5
# could be renamed to Triangular when that name has been fully deprecated
6
abstract type AbstractTriangular{T,S<:AbstractMatrix} <: AbstractMatrix{T} end
7

8
# First loop through all methods that don't need special care for upper/lower and unit diagonal
9
for t in (:LowerTriangular, :UnitLowerTriangular, :UpperTriangular,
10
          :UnitUpperTriangular)
11
    @eval begin
12
        struct $t{T,S<:AbstractMatrix{T}} <: AbstractTriangular{T,S}
13
            data::S
14

15
            function $t{T,S}(data) where {T,S<:AbstractMatrix{T}}
99,214✔
16
                require_one_based_indexing(data)
99,214✔
17
                checksquare(data)
99,215✔
18
                new{T,S}(data)
99,213✔
19
            end
20
        end
21
        $t(A::$t) = A
1,554✔
22
        $t{T}(A::$t{T}) where {T} = A
56✔
23
        function $t(A::AbstractMatrix)
99,180✔
24
            return $t{eltype(A), typeof(A)}(A)
99,180✔
25
        end
26
        function $t{T}(A::AbstractMatrix) where T
28✔
27
            $t(convert(AbstractMatrix{T}, A))
28✔
28
        end
29

30
        function $t{T}(A::$t) where T
21,343✔
31
            Anew = convert(AbstractMatrix{T}, A.data)
21,343✔
32
            $t(Anew)
21,103✔
33
        end
34
        Matrix(A::$t{T}) where {T} = Matrix{T}(A)
34,015✔
35

36
        AbstractMatrix{T}(A::$t) where {T} = $t{T}(A)
21,315✔
37

38
        size(A::$t, d) = size(A.data, d)
138,207✔
39
        size(A::$t) = size(A.data)
347,393✔
40

41
        # For A<:AbstractTriangular, similar(A[, neweltype]) should yield a matrix with the same
42
        # triangular type and underlying storage type as A. The following method covers these cases.
43
        similar(A::$t, ::Type{T}) where {T} = $t(similar(parent(A), T))
1,190✔
44
        # On the other hand, similar(A, [neweltype,] shape...) should yield a matrix of the underlying
45
        # storage type of A (not wrapped in a triangular type). The following method covers these cases.
46
        similar(A::$t, ::Type{T}, dims::Dims{N}) where {T,N} = similar(parent(A), T, dims)
15,341✔
47

48
        copy(A::$t) = $t(copy(A.data))
4,639✔
49

50
        real(A::$t{<:Real}) = A
81✔
51
        real(A::$t{<:Complex}) = (B = real(A.data); $t(B))
710✔
52
    end
53
end
54

55
similar(A::UpperTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
56
    UpperTriangular(similar(parent(parent(A)), T))
57
similar(A::UnitUpperTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
58
    UnitUpperTriangular(similar(parent(parent(A)), T))
59
similar(A::LowerTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
60
    LowerTriangular(similar(parent(parent(A)), T))
61
similar(A::UnitLowerTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
62
    UnitLowerTriangular(similar(parent(parent(A)), T))
63

64

65
"""
66
    LowerTriangular(A::AbstractMatrix)
67

68
Construct a `LowerTriangular` view of the matrix `A`.
69

70
# Examples
71
```jldoctest
72
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
73
3×3 Matrix{Float64}:
74
 1.0  2.0  3.0
75
 4.0  5.0  6.0
76
 7.0  8.0  9.0
77

78
julia> LowerTriangular(A)
79
3×3 LowerTriangular{Float64, Matrix{Float64}}:
80
 1.0   ⋅    ⋅
81
 4.0  5.0   ⋅
82
 7.0  8.0  9.0
83
```
84
"""
85
LowerTriangular
86
"""
87
    UpperTriangular(A::AbstractMatrix)
88

89
Construct an `UpperTriangular` view of the matrix `A`.
90

91
# Examples
92
```jldoctest
93
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
94
3×3 Matrix{Float64}:
95
 1.0  2.0  3.0
96
 4.0  5.0  6.0
97
 7.0  8.0  9.0
98

99
julia> UpperTriangular(A)
100
3×3 UpperTriangular{Float64, Matrix{Float64}}:
101
 1.0  2.0  3.0
102
  ⋅   5.0  6.0
103
  ⋅    ⋅   9.0
104
```
105
"""
106
UpperTriangular
107
"""
108
    UnitLowerTriangular(A::AbstractMatrix)
109

110
Construct a `UnitLowerTriangular` view of the matrix `A`.
111
Such a view has the [`oneunit`](@ref) of the [`eltype`](@ref)
112
of `A` on its diagonal.
113

114
# Examples
115
```jldoctest
116
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
117
3×3 Matrix{Float64}:
118
 1.0  2.0  3.0
119
 4.0  5.0  6.0
120
 7.0  8.0  9.0
121

122
julia> UnitLowerTriangular(A)
123
3×3 UnitLowerTriangular{Float64, Matrix{Float64}}:
124
 1.0   ⋅    ⋅
125
 4.0  1.0   ⋅
126
 7.0  8.0  1.0
127
```
128
"""
129
UnitLowerTriangular
130
"""
131
    UnitUpperTriangular(A::AbstractMatrix)
132

133
Construct an `UnitUpperTriangular` view of the matrix `A`.
134
Such a view has the [`oneunit`](@ref) of the [`eltype`](@ref)
135
of `A` on its diagonal.
136

137
# Examples
138
```jldoctest
139
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
140
3×3 Matrix{Float64}:
141
 1.0  2.0  3.0
142
 4.0  5.0  6.0
143
 7.0  8.0  9.0
144

145
julia> UnitUpperTriangular(A)
146
3×3 UnitUpperTriangular{Float64, Matrix{Float64}}:
147
 1.0  2.0  3.0
148
  ⋅   1.0  6.0
149
  ⋅    ⋅   1.0
150
```
151
"""
152
UnitUpperTriangular
153

154
const UpperOrUnitUpperTriangular{T,S} = Union{UpperTriangular{T,S}, UnitUpperTriangular{T,S}}
155
const LowerOrUnitLowerTriangular{T,S} = Union{LowerTriangular{T,S}, UnitLowerTriangular{T,S}}
156
const UpperOrLowerTriangular{T,S} = Union{UpperOrUnitUpperTriangular{T,S}, LowerOrUnitLowerTriangular{T,S}}
157

158
imag(A::UpperTriangular) = UpperTriangular(imag(A.data))
7✔
159
imag(A::LowerTriangular) = LowerTriangular(imag(A.data))
7✔
160
imag(A::UnitLowerTriangular) = LowerTriangular(tril!(imag(A.data),-1))
7✔
161
imag(A::UnitUpperTriangular) = UpperTriangular(triu!(imag(A.data),1))
7✔
162

163
Array(A::AbstractTriangular) = Matrix(A)
2,753✔
164
parent(A::UpperOrLowerTriangular) = A.data
46,835✔
165

166
# then handle all methods that requires specific handling of upper/lower and unit diagonal
167

168
function Matrix{T}(A::LowerTriangular) where T
8,659✔
169
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
8,659✔
170
    copyto!(B, A.data)
8,932✔
171
    tril!(B)
8,659✔
172
    B
8,659✔
173
end
174
function Matrix{T}(A::UnitLowerTriangular) where T
8,537✔
175
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
8,537✔
176
    copyto!(B, A.data)
8,910✔
177
    tril!(B)
8,537✔
178
    for i = 1:size(B,1)
17,074✔
179
        B[i,i] = 1
69,015✔
180
    end
129,493✔
181
    B
8,537✔
182
end
183
function Matrix{T}(A::UpperTriangular) where T
8,829✔
184
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
8,829✔
185
    copyto!(B, A.data)
9,809✔
186
    triu!(B)
8,829✔
187
    B
8,829✔
188
end
189
function Matrix{T}(A::UnitUpperTriangular) where T
8,705✔
190
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
8,705✔
191
    copyto!(B, A.data)
9,204✔
192
    triu!(B)
8,705✔
193
    for i = 1:size(B,1)
17,404✔
194
        B[i,i] = 1
69,843✔
195
    end
130,987✔
196
    B
8,705✔
197
end
198

199
function full!(A::LowerTriangular)
35✔
200
    B = A.data
35✔
201
    tril!(B)
35✔
202
    B
35✔
203
end
204
function full!(A::UnitLowerTriangular)
35✔
205
    B = A.data
35✔
206
    tril!(B)
35✔
207
    for i = 1:size(A,1)
70✔
208
        B[i,i] = 1
315✔
209
    end
595✔
210
    B
35✔
211
end
212
function full!(A::UpperTriangular)
35✔
213
    B = A.data
35✔
214
    triu!(B)
35✔
215
    B
35✔
216
end
217
function full!(A::UnitUpperTriangular)
35✔
218
    B = A.data
35✔
219
    triu!(B)
35✔
220
    for i = 1:size(A,1)
70✔
221
        B[i,i] = 1
315✔
222
    end
595✔
223
    B
35✔
224
end
225

226
getindex(A::UnitLowerTriangular{T}, i::Integer, j::Integer) where {T} =
805,924✔
227
    i > j ? A.data[i,j] : ifelse(i == j, oneunit(T), zero(T))
228
getindex(A::LowerTriangular, i::Integer, j::Integer) =
1,451,594✔
229
    i >= j ? A.data[i,j] : zero(A.data[j,i])
230
getindex(A::UnitUpperTriangular{T}, i::Integer, j::Integer) where {T} =
843,901✔
231
    i < j ? A.data[i,j] : ifelse(i == j, oneunit(T), zero(T))
232
getindex(A::UpperTriangular, i::Integer, j::Integer) =
1,985,266✔
233
    i <= j ? A.data[i,j] : zero(A.data[j,i])
234

235
function setindex!(A::UpperTriangular, x, i::Integer, j::Integer)
53,395✔
236
    if i > j
53,395✔
237
        x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " *
2,389✔
238
            "($i, $j) of an UpperTriangular matrix to a nonzero value ($x)"))
239
    else
240
        A.data[i,j] = x
51,261✔
241
    end
242
    return A
53,140✔
243
end
244

245
function setindex!(A::UnitUpperTriangular, x, i::Integer, j::Integer)
2,867✔
246
    if i > j
2,867✔
247
        x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " *
1,210✔
248
            "($i, $j) of a UnitUpperTriangular matrix to a nonzero value ($x)"))
249
    elseif i == j
1,909✔
250
        x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " *
251✔
251
            "of a UnitUpperTriangular matrix to a non-unit value ($x)"))
252
    else
253
        A.data[i,j] = x
1,658✔
254
    end
255
    return A
2,552✔
256
end
257

258
function setindex!(A::LowerTriangular, x, i::Integer, j::Integer)
6,935✔
259
    if i < j
6,935✔
260
        x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " *
1,640✔
261
            "($i, $j) of a LowerTriangular matrix to a nonzero value ($x)"))
262
    else
263
        A.data[i,j] = x
5,549✔
264
    end
265
    return A
6,681✔
266
end
267

268
function setindex!(A::UnitLowerTriangular, x, i::Integer, j::Integer)
2,867✔
269
    if i < j
2,867✔
270
        x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " *
1,210✔
271
            "($i, $j) of a UnitLowerTriangular matrix to a nonzero value ($x)"))
272
    elseif i == j
1,909✔
273
        x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " *
251✔
274
            "of a UnitLowerTriangular matrix to a non-unit value ($x)"))
275
    else
276
        A.data[i,j] = x
1,658✔
277
    end
278
    return A
2,552✔
279
end
280

281

282
## structured matrix methods ##
283
function Base.replace_in_print_matrix(A::Union{UpperTriangular,UnitUpperTriangular},
21,362✔
284
                                      i::Integer, j::Integer, s::AbstractString)
285
    return i <= j ? s : Base.replace_with_centered_mark(s)
21,362✔
286
end
287
function Base.replace_in_print_matrix(A::Union{LowerTriangular,UnitLowerTriangular},
20,084✔
288
                                      i::Integer, j::Integer, s::AbstractString)
289
    return i >= j ? s : Base.replace_with_centered_mark(s)
20,084✔
290
end
291

292
function istril(A::Union{LowerTriangular,UnitLowerTriangular}, k::Integer=0)
102✔
293
    k >= 0 && return true
102✔
294
    return _istril(A, k)
×
295
end
296
function istriu(A::Union{UpperTriangular,UnitUpperTriangular}, k::Integer=0)
940✔
297
    k <= 0 && return true
940✔
298
    return _istriu(A, k)
×
299
end
300
istril(A::Adjoint, k::Integer=0) = istriu(A.parent, -k)
5,732✔
301
istril(A::Transpose, k::Integer=0) = istriu(A.parent, -k)
1,449✔
302
istriu(A::Adjoint, k::Integer=0) = istril(A.parent, -k)
5,743✔
303
istriu(A::Transpose, k::Integer=0) = istril(A.parent, -k)
1,449✔
304

305
function tril!(A::UpperTriangular, k::Integer=0)
35✔
306
    n = size(A,1)
35✔
307
    if k < 0
35✔
308
        fill!(A.data,0)
974✔
309
        return A
14✔
310
    elseif k == 0
21✔
311
        for j in 1:n, i in 1:j-1
63✔
312
            A.data[i,j] = 0
252✔
313
        end
308✔
314
        return A
7✔
315
    else
316
        return UpperTriangular(tril!(A.data,k))
14✔
317
    end
318
end
319
triu!(A::UpperTriangular, k::Integer=0) = UpperTriangular(triu!(A.data,k))
186✔
320

321
function tril!(A::UnitUpperTriangular{T}, k::Integer=0) where T
35✔
322
    n = size(A,1)
35✔
323
    if k < 0
35✔
324
        fill!(A.data, zero(T))
1,134✔
325
        return UpperTriangular(A.data)
14✔
326
    elseif k == 0
21✔
327
        fill!(A.data, zero(T))
567✔
328
        for i in diagind(A)
14✔
329
            A.data[i] = oneunit(T)
63✔
330
        end
119✔
331
        return UpperTriangular(A.data)
7✔
332
    else
333
        for i in diagind(A)
28✔
334
            A.data[i] = oneunit(T)
126✔
335
        end
238✔
336
        return UpperTriangular(tril!(A.data,k))
14✔
337
    end
338
end
339

340
function triu!(A::UnitUpperTriangular, k::Integer=0)
35✔
341
    for i in diagind(A)
70✔
342
        A.data[i] = oneunit(eltype(A))
315✔
343
    end
595✔
344
    return triu!(UpperTriangular(A.data),k)
35✔
345
end
346

347
function triu!(A::LowerTriangular, k::Integer=0)
35✔
348
    n = size(A,1)
35✔
349
    if k > 0
35✔
350
        fill!(A.data,0)
974✔
351
        return A
14✔
352
    elseif k == 0
21✔
353
        for j in 1:n, i in j+1:n
63✔
354
            A.data[i,j] = 0
252✔
355
        end
308✔
356
        return A
7✔
357
    else
358
        return LowerTriangular(triu!(A.data,k))
14✔
359
    end
360
end
361

362
tril!(A::LowerTriangular, k::Integer=0) = LowerTriangular(tril!(A.data,k))
70✔
363

364
function triu!(A::UnitLowerTriangular{T}, k::Integer=0) where T
35✔
365
    n = size(A,1)
35✔
366
    if k > 0
35✔
367
        fill!(A.data, zero(T))
1,134✔
368
        return LowerTriangular(A.data)
14✔
369
    elseif k == 0
21✔
370
        fill!(A.data, zero(T))
567✔
371
        for i in diagind(A)
14✔
372
            A.data[i] = oneunit(T)
63✔
373
        end
119✔
374
        return LowerTriangular(A.data)
7✔
375
    else
376
        for i in diagind(A)
28✔
377
            A.data[i] = oneunit(T)
126✔
378
        end
238✔
379
        return LowerTriangular(triu!(A.data,k))
14✔
380
    end
381
end
382

383
function tril!(A::UnitLowerTriangular, k::Integer=0)
35✔
384
    for i in diagind(A)
70✔
385
        A.data[i] = oneunit(eltype(A))
315✔
386
    end
595✔
387
    return tril!(LowerTriangular(A.data),k)
35✔
388
end
389

390
adjoint(A::LowerTriangular) = UpperTriangular(adjoint(A.data))
4,372✔
391
adjoint(A::UpperTriangular) = LowerTriangular(adjoint(A.data))
4,563✔
392
adjoint(A::UnitLowerTriangular) = UnitUpperTriangular(adjoint(A.data))
4,510✔
393
adjoint(A::UnitUpperTriangular) = UnitLowerTriangular(adjoint(A.data))
4,086✔
394
transpose(A::LowerTriangular) = UpperTriangular(transpose(A.data))
4,250✔
395
transpose(A::UpperTriangular) = LowerTriangular(transpose(A.data))
4,109✔
396
transpose(A::UnitLowerTriangular) = UnitUpperTriangular(transpose(A.data))
4,721✔
397
transpose(A::UnitUpperTriangular) = UnitLowerTriangular(transpose(A.data))
4,082✔
398

399
transpose!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L', false, true))
21✔
400
transpose!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L', false, true))
21✔
401
transpose!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U', false, true))
21✔
402
transpose!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U', false, true))
21✔
403
adjoint!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L' , true, true))
21✔
404
adjoint!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L' , true, true))
21✔
405
adjoint!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U' , true, true))
21✔
406
adjoint!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U' , true, true))
21✔
407

408
diag(A::LowerTriangular) = diag(A.data)
53✔
409
diag(A::UnitLowerTriangular) = fill(one(eltype(A)), size(A,1))
159✔
410
diag(A::UpperTriangular) = diag(A.data)
179✔
411
diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1))
321✔
412

413
# Unary operations
414
-(A::LowerTriangular) = LowerTriangular(-A.data)
9✔
415
-(A::UpperTriangular) = UpperTriangular(-A.data)
152✔
416
function -(A::UnitLowerTriangular)
9✔
417
    Anew = -A.data
9✔
418
    for i = 1:size(A, 1)
18✔
419
        Anew[i, i] = -1
69✔
420
    end
129✔
421
    LowerTriangular(Anew)
9✔
422
end
423
function -(A::UnitUpperTriangular)
9✔
424
    Anew = -A.data
9✔
425
    for i = 1:size(A, 1)
18✔
426
        Anew[i, i] = -1
69✔
427
    end
129✔
428
    UpperTriangular(Anew)
9✔
429
end
430

431
tr(A::LowerTriangular) = tr(A.data)
7✔
432
tr(A::UnitLowerTriangular) = size(A, 1) * oneunit(eltype(A))
7✔
433
tr(A::UpperTriangular) = tr(A.data)
7✔
434
tr(A::UnitUpperTriangular) = size(A, 1) * oneunit(eltype(A))
7✔
435

436
# copy and scale
437
function copyto!(A::T, B::T) where T<:Union{UpperTriangular,UnitUpperTriangular}
1,601✔
438
    n = size(B,1)
1,601✔
439
    for j = 1:n
3,202✔
440
        for i = 1:(isa(B, UnitUpperTriangular) ? j-1 : j)
13,414✔
441
            @inbounds A[i,j] = B[i,j]
21,972✔
442
        end
37,251✔
443
    end
11,841✔
444
    return A
1,601✔
445
end
446
function copyto!(A::T, B::T) where T<:Union{LowerTriangular,UnitLowerTriangular}
56✔
447
    n = size(B,1)
56✔
448
    for j = 1:n
112✔
449
        for i = (isa(B, UnitLowerTriangular) ? j+1 : j):n
952✔
450
            @inbounds A[i,j] = B[i,j]
2,149✔
451
        end
3,836✔
452
    end
924✔
453
    return A
56✔
454
end
455

456
# Define `mul!` for (Unit){Upper,Lower}Triangular matrices times a
457
# number.
458
for (Trig, UnitTrig) in Any[(UpperTriangular, UnitUpperTriangular),
459
                            (LowerTriangular, UnitLowerTriangular)]
460
    for (TB, TC) in Any[(Trig, Number),
461
                        (Number, Trig),
462
                        (UnitTrig, Number),
463
                        (Number, UnitTrig)]
464
        @eval @inline mul!(A::$Trig, B::$TB, C::$TC, alpha::Number, beta::Number) =
3,498✔
465
            _mul!(A, B, C, MulAddMul(alpha, beta))
466
    end
467
end
468

469
@inline function _mul!(A::UpperTriangular, B::UpperTriangular, c::Number, _add::MulAddMul)
759✔
470
    n = checksquare(B)
759✔
471
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
759✔
472
    for j = 1:n
1,518✔
473
        for i = 1:j
5,478✔
474
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
7,375✔
475
        end
12,011✔
476
    end
4,719✔
477
    return A
759✔
478
end
479
@inline function _mul!(A::UpperTriangular, c::Number, B::UpperTriangular, _add::MulAddMul)
15✔
480
    n = checksquare(B)
15✔
481
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
15✔
482
    for j = 1:n
30✔
483
        for i = 1:j
286✔
484
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
755✔
485
        end
1,367✔
486
    end
271✔
487
    return A
15✔
488
end
489
@inline function _mul!(A::UpperTriangular, B::UnitUpperTriangular, c::Number, _add::MulAddMul)
7✔
490
    n = checksquare(B)
7✔
491
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
492
    for j = 1:n
14✔
493
        @inbounds _modify!(_add, c, A, (j,j))
63✔
494
        for i = 1:(j - 1)
119✔
495
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
252✔
496
        end
448✔
497
    end
119✔
498
    return A
7✔
499
end
500
@inline function _mul!(A::UpperTriangular, c::Number, B::UnitUpperTriangular, _add::MulAddMul)
7✔
501
    n = checksquare(B)
7✔
502
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
503
    for j = 1:n
14✔
504
        @inbounds _modify!(_add, c, A, (j,j))
63✔
505
        for i = 1:(j - 1)
119✔
506
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
252✔
507
        end
448✔
508
    end
119✔
509
    return A
7✔
510
end
511
@inline function _mul!(A::LowerTriangular, B::LowerTriangular, c::Number, _add::MulAddMul)
41✔
512
    n = checksquare(B)
41✔
513
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
41✔
514
    for j = 1:n
82✔
515
        for i = j:n
442✔
516
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
911✔
517
        end
1,601✔
518
    end
401✔
519
    return A
41✔
520
end
521
@inline function _mul!(A::LowerTriangular, c::Number, B::LowerTriangular, _add::MulAddMul)
15✔
522
    n = checksquare(B)
15✔
523
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
15✔
524
    for j = 1:n
30✔
525
        for i = j:n
286✔
526
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
755✔
527
        end
1,367✔
528
    end
271✔
529
    return A
15✔
530
end
531
@inline function _mul!(A::LowerTriangular, B::UnitLowerTriangular, c::Number, _add::MulAddMul)
7✔
532
    n = checksquare(B)
7✔
533
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
534
    for j = 1:n
14✔
535
        @inbounds _modify!(_add, c, A, (j,j))
63✔
536
        for i = (j + 1):n
119✔
537
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
252✔
538
        end
448✔
539
    end
119✔
540
    return A
7✔
541
end
542
@inline function _mul!(A::LowerTriangular, c::Number, B::UnitLowerTriangular, _add::MulAddMul)
7✔
543
    n = checksquare(B)
7✔
544
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
545
    for j = 1:n
14✔
546
        @inbounds _modify!(_add, c, A, (j,j))
63✔
547
        for i = (j + 1):n
119✔
548
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
252✔
549
        end
448✔
550
    end
119✔
551
    return A
7✔
552
end
553

554
rmul!(A::Union{UpperTriangular,LowerTriangular}, c::Number) = mul!(A, A, c)
246✔
555
lmul!(c::Number, A::Union{UpperTriangular,LowerTriangular}) = mul!(A, c, A)
30✔
556

557
function dot(x::AbstractVector, A::UpperTriangular, y::AbstractVector)
42✔
558
    require_one_based_indexing(x, y)
42✔
559
    m = size(A, 1)
42✔
560
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
561
    if iszero(m)
42✔
562
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
563
    end
564
    x₁ = x[1]
42✔
565
    r = dot(x₁, A[1,1], y[1])
42✔
566
    @inbounds for j in 2:m
84✔
567
        yj = y[j]
336✔
568
        if !iszero(yj)
336✔
569
            temp = adjoint(A[1,j]) * x₁
336✔
570
            @simd for i in 2:j
336✔
571
                temp += adjoint(A[i,j]) * x[i]
1,512✔
572
            end
×
573
            r += dot(temp, yj)
336✔
574
        end
575
    end
630✔
576
    return r
42✔
577
end
578
function dot(x::AbstractVector, A::UnitUpperTriangular, y::AbstractVector)
42✔
579
    require_one_based_indexing(x, y)
42✔
580
    m = size(A, 1)
42✔
581
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
582
    if iszero(m)
42✔
583
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
584
    end
585
    x₁ = first(x)
42✔
586
    r = dot(x₁, y[1])
42✔
587
    @inbounds for j in 2:m
84✔
588
        yj = y[j]
336✔
589
        if !iszero(yj)
336✔
590
            temp = adjoint(A[1,j]) * x₁
336✔
591
            @simd for i in 2:j-1
378✔
592
                temp += adjoint(A[i,j]) * x[i]
1,176✔
593
            end
×
594
            r += dot(temp, yj)
420✔
595
            r += dot(x[j], yj)
336✔
596
        end
597
    end
630✔
598
    return r
42✔
599
end
600
function dot(x::AbstractVector, A::LowerTriangular, y::AbstractVector)
42✔
601
    require_one_based_indexing(x, y)
42✔
602
    m = size(A, 1)
42✔
603
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
604
    if iszero(m)
42✔
605
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
606
    end
607
    r = zero(typeof(dot(first(x), first(A), first(y))))
42✔
608
    @inbounds for j in 1:m
84✔
609
        yj = y[j]
378✔
610
        if !iszero(yj)
378✔
611
            temp = adjoint(A[j,j]) * x[j]
378✔
612
            @simd for i in j+1:m
420✔
613
                temp += adjoint(A[i,j]) * x[i]
1,512✔
614
            end
×
615
            r += dot(temp, yj)
378✔
616
        end
617
    end
714✔
618
    return r
42✔
619
end
620
function dot(x::AbstractVector, A::UnitLowerTriangular, y::AbstractVector)
42✔
621
    require_one_based_indexing(x, y)
42✔
622
    m = size(A, 1)
42✔
623
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
624
    if iszero(m)
42✔
625
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
626
    end
627
    r = zero(typeof(dot(first(x), first(y))))
42✔
628
    @inbounds for j in 1:m
84✔
629
        yj = y[j]
378✔
630
        if !iszero(yj)
378✔
631
            temp = x[j]
378✔
632
            @simd for i in j+1:m
420✔
633
                temp += adjoint(A[i,j]) * x[i]
1,876✔
634
            end
×
635
            r += dot(temp, yj)
491✔
636
        end
637
    end
714✔
638
    return r
42✔
639
end
640

641
fillstored!(A::LowerTriangular, x)     = (fillband!(A.data, x, 1-size(A,1), 0); A)
2✔
642
fillstored!(A::UnitLowerTriangular, x) = (fillband!(A.data, x, 1-size(A,1), -1); A)
2✔
643
fillstored!(A::UpperTriangular, x)     = (fillband!(A.data, x, 0, size(A,2)-1); A)
2✔
644
fillstored!(A::UnitUpperTriangular, x) = (fillband!(A.data, x, 1, size(A,2)-1); A)
×
645

646
# Binary operations
647
+(A::UpperTriangular, B::UpperTriangular) = UpperTriangular(A.data + B.data)
159✔
648
+(A::LowerTriangular, B::LowerTriangular) = LowerTriangular(A.data + B.data)
63✔
649
+(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(A.data + triu(B.data, 1) + I)
50✔
650
+(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(A.data + tril(B.data, -1) + I)
50✔
651
+(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(triu(A.data, 1) + B.data + I)
50✔
652
+(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(tril(A.data, -1) + B.data + I)
49✔
653
+(A::UnitUpperTriangular, B::UnitUpperTriangular) = UpperTriangular(triu(A.data, 1) + triu(B.data, 1) + 2I)
49✔
654
+(A::UnitLowerTriangular, B::UnitLowerTriangular) = LowerTriangular(tril(A.data, -1) + tril(B.data, -1) + 2I)
49✔
655
+(A::AbstractTriangular, B::AbstractTriangular) = copyto!(similar(parent(A)), A) + copyto!(similar(parent(B)), B)
406✔
656

657
-(A::UpperTriangular, B::UpperTriangular) = UpperTriangular(A.data - B.data)
253✔
658
-(A::LowerTriangular, B::LowerTriangular) = LowerTriangular(A.data - B.data)
244✔
659
-(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(A.data - triu(B.data, 1) - I)
50✔
660
-(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(A.data - tril(B.data, -1) - I)
49✔
661
-(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(triu(A.data, 1) - B.data + I)
50✔
662
-(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(tril(A.data, -1) - B.data + I)
49✔
663
-(A::UnitUpperTriangular, B::UnitUpperTriangular) = UpperTriangular(triu(A.data, 1) - triu(B.data, 1))
57✔
664
-(A::UnitLowerTriangular, B::UnitLowerTriangular) = LowerTriangular(tril(A.data, -1) - tril(B.data, -1))
56✔
665
-(A::AbstractTriangular, B::AbstractTriangular) = copyto!(similar(parent(A)), A) - copyto!(similar(parent(B)), B)
396✔
666

667
######################
668
# BlasFloat routines #
669
######################
670

671
lmul!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) # is this necessary?
112✔
672

673
mul!(C::AbstractVector, A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractVecOrMat}) =
×
674
    (B = transB.parent; lmul!(A, transpose!(C, B)))
×
675
mul!(C::AbstractMatrix, A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractVecOrMat}) =
72✔
676
    (B = transB.parent; lmul!(A, transpose!(C, B)))
72✔
677
mul!(C::AbstractMatrix, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) =
72✔
678
    (B = adjB.parent; lmul!(A, adjoint!(C, B)))
72✔
679
mul!(C::AbstractVecOrMat, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) =
×
680
    (B = adjB.parent; lmul!(A, adjoint!(C, B)))
×
681

682
# The three methods are necessary to avoid ambiguities with definitions in matmul.jl
683
mul!(C::AbstractVector  , A::AbstractTriangular, B::AbstractVector)   = lmul!(A, copyto!(C, B))
300✔
684
mul!(C::AbstractMatrix  , A::AbstractTriangular, B::AbstractVecOrMat) = lmul!(A, copyto!(C, B))
842✔
685
mul!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = lmul!(A, copyto!(C, B))
×
686

687
@inline mul!(C::AbstractMatrix, A::AbstractTriangular, B::Adjoint{<:Any,<:AbstractVecOrMat}, alpha::Number, beta::Number) =
297✔
688
    mul!(C, A, copy(B), alpha, beta)
689
@inline mul!(C::AbstractMatrix, A::AbstractTriangular, B::Transpose{<:Any,<:AbstractVecOrMat}, alpha::Number, beta::Number) =
270✔
690
    mul!(C, A, copy(B), alpha, beta)
691

692
# preserve triangular structure in in-place multiplication
693
for (cty, aty, bty) in ((:UpperTriangular, :UpperTriangular, :UpperTriangular),
694
                        (:UpperTriangular, :UpperTriangular, :UnitUpperTriangular),
695
                        (:UpperTriangular, :UnitUpperTriangular, :UpperTriangular),
696
                        (:UnitUpperTriangular, :UnitUpperTriangular, :UnitUpperTriangular),
697
                        (:LowerTriangular, :LowerTriangular, :LowerTriangular),
698
                        (:LowerTriangular, :LowerTriangular, :UnitLowerTriangular),
699
                        (:LowerTriangular, :UnitLowerTriangular, :LowerTriangular),
700
                        (:UnitLowerTriangular, :UnitLowerTriangular, :UnitLowerTriangular))
701
    @eval function mul!(C::$cty, A::$aty, B::$bty)
1,245✔
702
        lmul!(A, copyto!(parent(C), B))
2,490✔
703
        return C
1,245✔
704
    end
705

706
    @eval @inline function mul!(C::$cty, A::$aty, B::$bty, alpha::Number, beta::Number)
16✔
707
        if isone(alpha) && iszero(beta)
16✔
708
            return mul!(C, A, B)
×
709
        else
710
            return generic_matmatmul!(C, 'N', 'N', A, B, MulAddMul(alpha, beta))
16✔
711
        end
712
    end
713
end
714

715
# direct multiplication/division
716
for (t, uploc, isunitc) in ((:LowerTriangular, 'L', 'N'),
717
                            (:UnitLowerTriangular, 'L', 'U'),
718
                            (:UpperTriangular, 'U', 'N'),
719
                            (:UnitUpperTriangular, 'U', 'U'))
720
    @eval begin
721
        # Vector multiplication
722
        lmul!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} =
858✔
723
            BLAS.trmv!($uploc, 'N', $isunitc, A.data, b)
724

725
        # Matrix multiplication
726
        lmul!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} =
8,146✔
727
            BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B)
728
        rmul!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} =
2,094✔
729
            BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A)
730

731
        # Left division
732
        ldiv!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
6,882✔
733
            LAPACK.trtrs!($uploc, 'N', $isunitc, A.data, B)
734

735
        # Right division
736
        rdiv!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} =
4,041✔
737
            BLAS.trsm!('R', $uploc, 'N', $isunitc, one(T), B.data, A)
738

739
        # Matrix inverse
740
        inv!(A::$t{T,S}) where {T<:BlasFloat,S<:StridedMatrix} =
16✔
741
            $t{T,S}(LAPACK.trtri!($uploc, $isunitc, A.data))
742

743
        # Error bounds for triangular solve
744
        errorbounds(A::$t{T,<:StridedMatrix}, X::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
160✔
745
            LAPACK.trrfs!($uploc, 'N', $isunitc, A.data, B, X)
746

747
        # Condition numbers
748
        function cond(A::$t{<:BlasFloat,<:StridedMatrix}, p::Real=2)
144✔
749
            checksquare(A)
144✔
750
            if p == 1
144✔
751
                return inv(LAPACK.trcon!('O', $uploc, $isunitc, A.data))
64✔
752
            elseif p == Inf
80✔
753
                return inv(LAPACK.trcon!('I', $uploc, $isunitc, A.data))
64✔
754
            else # use fallback
755
                return cond(copyto!(similar(parent(A)), A), p)
16✔
756
            end
757
        end
758
    end
759
end
760

761
# adjoint/transpose multiplication ('uploc' reversed)
762
for (t, uploc, isunitc) in ((:LowerTriangular, 'U', 'N'),
763
                            (:UnitLowerTriangular, 'U', 'U'),
764
                            (:UpperTriangular, 'L', 'N'),
765
                            (:UnitUpperTriangular, 'L', 'U'))
766
    @eval begin
767
        # Vector multiplication
768
        lmul!(A::$t{<:Any,<:Transpose{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasFloat} =
124✔
769
            BLAS.trmv!($uploc, 'T', $isunitc, parent(parent(A)), b)
770
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasReal} =
72✔
771
            BLAS.trmv!($uploc, 'T', $isunitc, parent(parent(A)), b)
772
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasComplex} =
100✔
773
            BLAS.trmv!($uploc, 'C', $isunitc, parent(parent(A)), b)
774

775
        # Matrix multiplication
776
        lmul!(A::$t{<:Any,<:Transpose{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasFloat} =
1,072✔
777
            BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), parent(parent(A)), B)
778
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasComplex} =
667✔
779
            BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), parent(parent(A)), B)
780
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasReal} =
451✔
781
            BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), parent(parent(A)), B)
782

783
        rmul!(A::StridedMatrix{T}, B::$t{<:Any,<:Transpose{T,<:StridedMatrix}}) where {T<:BlasFloat} =
444✔
784
            BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
785
        rmul!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasComplex} =
200✔
786
            BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), parent(parent(B)), A)
787
        rmul!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasReal} =
217✔
788
            BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
789

790
        # Left division
791
        ldiv!(A::$t{<:Any,<:Transpose{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
900✔
792
            LAPACK.trtrs!($uploc, 'T', $isunitc, parent(parent(A)), B)
793
        ldiv!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasReal} =
838✔
794
            LAPACK.trtrs!($uploc, 'T', $isunitc, parent(parent(A)), B)
795
        ldiv!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasComplex} =
789✔
796
            LAPACK.trtrs!($uploc, 'C', $isunitc, parent(parent(A)), B)
797

798
        # Right division
799
        rdiv!(A::StridedMatrix{T}, B::$t{<:Any,<:Transpose{T,<:StridedMatrix}}) where {T<:BlasFloat} =
328✔
800
            BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
801
        rdiv!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasReal} =
152✔
802
            BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
803
        rdiv!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasComplex} =
176✔
804
            BLAS.trsm!('R', $uploc, 'C', $isunitc, one(T), parent(parent(B)), A)
805
    end
806
end
807

808
function inv(A::LowerTriangular{T}) where T
61✔
809
    S = typeof((zero(T)*one(T) + zero(T))/one(T))
61✔
810
    LowerTriangular(ldiv!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1))))
61✔
811
end
812
function inv(A::UpperTriangular{T}) where T
298✔
813
    S = typeof((zero(T)*one(T) + zero(T))/one(T))
298✔
814
    UpperTriangular(ldiv!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1))))
298✔
815
end
816
inv(A::UnitUpperTriangular{T}) where {T} = UnitUpperTriangular(ldiv!(A, Matrix{T}(I, size(A, 1), size(A, 1))))
19✔
817
inv(A::UnitLowerTriangular{T}) where {T} = UnitLowerTriangular(ldiv!(A, Matrix{T}(I, size(A, 1), size(A, 1))))
19✔
818

819
errorbounds(A::AbstractTriangular{T,<:AbstractMatrix}, X::AbstractVecOrMat{T}, B::AbstractVecOrMat{T}) where {T<:Union{BigFloat,Complex{BigFloat}}} =
×
820
    error("not implemented yet! Please submit a pull request.")
821
function errorbounds(A::AbstractTriangular{TA,<:AbstractMatrix}, X::AbstractVecOrMat{TX}, B::AbstractVecOrMat{TB}) where {TA<:Number,TX<:Number,TB<:Number}
128✔
822
    TAXB = promote_type(TA, TB, TX, Float32)
128✔
823
    errorbounds(convert(AbstractMatrix{TAXB}, A), convert(AbstractArray{TAXB}, X), convert(AbstractArray{TAXB}, B))
128✔
824
end
825

826
# Eigensystems
827
## Notice that trecv works for quasi-triangular matrices and therefore the lower sub diagonal must be zeroed before calling the subroutine
828
function eigvecs(A::UpperTriangular{<:BlasFloat,<:StridedMatrix})
5✔
829
    LAPACK.trevc!('R', 'A', BlasInt[], triu!(A.data))
5✔
830
end
831
function eigvecs(A::UnitUpperTriangular{<:BlasFloat,<:StridedMatrix})
5✔
832
    for i = 1:size(A, 1)
10✔
833
        A.data[i,i] = 1
45✔
834
    end
85✔
835
    LAPACK.trevc!('R', 'A', BlasInt[], triu!(A.data))
5✔
836
end
837
function eigvecs(A::LowerTriangular{<:BlasFloat,<:StridedMatrix})
5✔
838
    LAPACK.trevc!('L', 'A', BlasInt[], copy(tril!(A.data)'))
5✔
839
end
840
function eigvecs(A::UnitLowerTriangular{<:BlasFloat,<:StridedMatrix})
5✔
841
    for i = 1:size(A, 1)
10✔
842
        A.data[i,i] = 1
45✔
843
    end
85✔
844
    LAPACK.trevc!('L', 'A', BlasInt[], copy(tril!(A.data)'))
5✔
845
end
846

847
####################
848
# Generic routines #
849
####################
850

851
for (t, unitt) in ((UpperTriangular, UnitUpperTriangular),
852
                   (LowerTriangular, UnitLowerTriangular))
853
    @eval begin
854
        (*)(A::$t, x::Number) = $t(A.data*x)
36✔
855

856
        function (*)(A::$unitt, x::Number)
20✔
857
            B = A.data*x
20✔
858
            for i = 1:size(A, 1)
40✔
859
                B[i,i] = x
180✔
860
            end
340✔
861
            $t(B)
20✔
862
        end
863

864
        (*)(x::Number, A::$t) = $t(x*A.data)
918✔
865

866
        function (*)(x::Number, A::$unitt)
36✔
867
            B = x*A.data
36✔
868
            for i = 1:size(A, 1)
72✔
869
                B[i,i] = x
324✔
870
            end
612✔
871
            $t(B)
36✔
872
        end
873

874
        (/)(A::$t, x::Number) = $t(A.data/x)
52✔
875

876
        function (/)(A::$unitt, x::Number)
14✔
877
            B = A.data/x
14✔
878
            invx = inv(x)
14✔
879
            for i = 1:size(A, 1)
28✔
880
                B[i,i] = invx
126✔
881
            end
238✔
882
            $t(B)
14✔
883
        end
884

885
        (\)(x::Number, A::$t) = $t(x\A.data)
14✔
886

887
        function (\)(x::Number, A::$unitt)
14✔
888
            B = x\A.data
14✔
889
            invx = inv(x)
14✔
890
            for i = 1:size(A, 1)
28✔
891
                B[i,i] = invx
126✔
892
            end
238✔
893
            $t(B)
14✔
894
        end
895
    end
896
end
897

898
## Generic triangular multiplication
899
function lmul!(A::UpperTriangular, B::AbstractVecOrMat)
2,033✔
900
    require_one_based_indexing(A, B)
2,033✔
901
    m, n = size(B, 1), size(B, 2)
2,033✔
902
    if m != size(A, 1)
2,033✔
903
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
904
    end
905
    @inbounds for j = 1:n
3,502✔
906
        for i = 1:m
24,710✔
907
            Bij = A.data[i,i]*B[i,j]
110,497✔
908
            for k = i + 1:m
208,639✔
909
                Bij += A.data[i,k]*B[k,j]
441,810✔
910
            end
784,674✔
911
            B[i,j] = Bij
110,497✔
912
        end
208,639✔
913
    end
22,959✔
914
    B
1,751✔
915
end
916
function lmul!(A::UnitUpperTriangular, B::AbstractVecOrMat)
1,721✔
917
    require_one_based_indexing(A, B)
1,721✔
918
    m, n = size(B, 1), size(B, 2)
1,721✔
919
    if m != size(A, 1)
1,721✔
920
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
921
    end
922
    @inbounds for j = 1:n
2,878✔
923
        for i = 1:m
22,090✔
924
            Bij = B[i,j]
98,800✔
925
            for k = i + 1:m
186,555✔
926
                Bij += A.data[i,k]*B[k,j]
394,075✔
927
            end
700,395✔
928
            B[i,j] = Bij
98,800✔
929
        end
186,555✔
930
    end
20,651✔
931
    B
1,439✔
932
end
933
function lmul!(A::LowerTriangular, B::AbstractVecOrMat)
1,803✔
934
    require_one_based_indexing(A, B)
1,803✔
935
    m, n = size(B, 1), size(B, 2)
1,803✔
936
    if m != size(A, 1)
1,803✔
937
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
938
    end
939
    @inbounds for j = 1:n
3,042✔
940
        for i = m:-1:1
23,054✔
941
            Bij = A.data[i,i]*B[i,j]
102,764✔
942
            for k = 1:i - 1
194,001✔
943
                Bij += A.data[i,k]*B[k,j]
410,790✔
944
            end
729,491✔
945
            B[i,j] = Bij
102,764✔
946
        end
194,001✔
947
    end
21,533✔
948
    B
1,521✔
949
end
950
function lmul!(A::UnitLowerTriangular, B::AbstractVecOrMat)
1,718✔
951
    require_one_based_indexing(A, B)
1,718✔
952
    m, n = size(B, 1), size(B, 2)
1,718✔
953
    if m != size(A, 1)
1,718✔
954
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
955
    end
956
    @inbounds for j = 1:n
2,872✔
957
        for i = m:-1:1
22,084✔
958
            Bij = B[i,j]
98,770✔
959
            for k = 1:i - 1
186,498✔
960
                Bij += A.data[i,k]*B[k,j]
393,940✔
961
            end
700,152✔
962
            B[i,j] = Bij
98,770✔
963
        end
186,498✔
964
    end
20,648✔
965
    B
1,436✔
966
end
967

968
function rmul!(A::AbstractMatrix, B::UpperTriangular)
496✔
969
    require_one_based_indexing(A, B)
496✔
970
    m, n = size(A)
496✔
971
    if size(B, 1) != n
496✔
972
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
973
    end
974
    @inbounds for i = 1:m
428✔
975
        for j = n:-1:1
3,876✔
976
            Aij = A[i,j]*B.data[j,j]
17,562✔
977
            for k = 1:j - 1
33,186✔
978
                Aij += A[i,k]*B.data[k,j]
70,848✔
979
            end
126,072✔
980
            A[i,j] = Aij
17,562✔
981
        end
33,186✔
982
    end
3,662✔
983
    A
214✔
984
end
985
function rmul!(A::AbstractMatrix, B::UnitUpperTriangular)
488✔
986
    require_one_based_indexing(A, B)
488✔
987
    m, n = size(A)
488✔
988
    if size(B, 1) != n
488✔
989
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
990
    end
991
    @inbounds for i = 1:m
412✔
992
        for j = n:-1:1
3,716✔
993
            Aij = A[i,j]
16,762✔
994
            for k = 1:j - 1
31,666✔
995
                Aij += A[i,k]*B.data[k,j]
67,248✔
996
            end
119,592✔
997
            A[i,j] = Aij
16,762✔
998
        end
31,666✔
999
    end
3,510✔
1000
    A
206✔
1001
end
1002

1003
function rmul!(A::AbstractMatrix, B::LowerTriangular)
488✔
1004
    require_one_based_indexing(A, B)
488✔
1005
    m, n = size(A)
488✔
1006
    if size(B, 1) != n
488✔
1007
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
1008
    end
1009
    @inbounds for i = 1:m
412✔
1010
        for j = 1:n
3,716✔
1011
            Aij = A[i,j]*B.data[j,j]
16,762✔
1012
            for k = j + 1:n
31,666✔
1013
                Aij += A[i,k]*B.data[k,j]
67,248✔
1014
            end
119,592✔
1015
            A[i,j] = Aij
16,762✔
1016
        end
31,666✔
1017
    end
3,510✔
1018
    A
206✔
1019
end
1020
function rmul!(A::AbstractMatrix, B::UnitLowerTriangular)
488✔
1021
    require_one_based_indexing(A, B)
488✔
1022
    m, n = size(A)
488✔
1023
    if size(B, 1) != n
488✔
1024
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
1025
    end
1026
    @inbounds for i = 1:m
412✔
1027
        for j = 1:n
3,716✔
1028
            Aij = A[i,j]
16,762✔
1029
            for k = j + 1:n
31,666✔
1030
                Aij += A[i,k]*B.data[k,j]
67,248✔
1031
            end
119,592✔
1032
            A[i,j] = Aij
16,762✔
1033
        end
31,666✔
1034
    end
3,510✔
1035
    A
206✔
1036
end
1037

1038
#Generic solver using naive substitution
1039
# manually hoisting b[j] significantly improves performance as of Dec 2015
1040
# manually eliding bounds checking significantly improves performance as of Dec 2015
1041
# directly indexing A.data rather than A significantly improves performance as of Dec 2015
1042
# replacing repeated references to A.data with [Adata = A.data and references to Adata]
1043
# does not significantly impact performance as of Dec 2015
1044
# replacing repeated references to A.data[j,j] with [Ajj = A.data[j,j] and references to Ajj]
1045
# does not significantly impact performance as of Dec 2015
1046
function ldiv!(A::UpperTriangular, b::AbstractVector)
14,351✔
1047
    require_one_based_indexing(A, b)
14,351✔
1048
    n = size(A, 2)
14,351✔
1049
    if !(n == length(b))
14,351✔
1050
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
15✔
1051
    end
1052
    @inbounds for j in n:-1:1
28,672✔
1053
        iszero(A.data[j,j]) && throw(SingularException(j))
136,104✔
1054
        bj = b[j] = A.data[j,j] \ b[j]
135,587✔
1055
        for i in j-1:-1:1 # counterintuitively 1:j-1 performs slightly better
255,434✔
1056
            b[i] -= A.data[i,j] * bj
657,670✔
1057
        end
1,187,524✔
1058
    end
255,434✔
1059
    return b
14,298✔
1060
end
1061
function ldiv!(A::UnitUpperTriangular, b::AbstractVector)
3,470✔
1062
    require_one_based_indexing(A, b)
3,470✔
1063
    n = size(A, 2)
3,470✔
1064
    if !(n == length(b))
3,470✔
1065
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
21✔
1066
    end
1067
    @inbounds for j in n:-1:1
6,898✔
1068
        bj = b[j]
31,727✔
1069
        for i in j-1:-1:1 # counterintuitively 1:j-1 performs slightly better
59,601✔
1070
            b[i] -= A.data[i,j] * bj
133,083✔
1071
        end
229,546✔
1072
    end
59,601✔
1073
    return b
3,449✔
1074
end
1075
function ldiv!(A::LowerTriangular, b::AbstractVector)
10,809✔
1076
    require_one_based_indexing(A, b)
10,809✔
1077
    n = size(A, 2)
10,809✔
1078
    if !(n == length(b))
10,809✔
1079
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
15✔
1080
    end
1081
    @inbounds for j in 1:n
21,588✔
1082
        iszero(A.data[j,j]) && throw(SingularException(j))
98,789✔
1083
        bj = b[j] = A.data[j,j] \ b[j]
98,301✔
1084
        for i in j+1:n
184,346✔
1085
            b[i] -= A.data[i,j] * bj
398,228✔
1086
        end
702,331✔
1087
    end
184,346✔
1088
    return b
10,756✔
1089
end
1090
function ldiv!(A::UnitLowerTriangular, b::AbstractVector)
4,965✔
1091
    require_one_based_indexing(A, b)
4,965✔
1092
    n = size(A, 2)
4,965✔
1093
    if !(n == length(b))
4,965✔
1094
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
21✔
1095
    end
1096
    @inbounds for j in 1:n
9,888✔
1097
        bj = b[j]
50,360✔
1098
        for i in j+1:n
95,296✔
1099
            b[i] -= A.data[i,j] * bj
316,218✔
1100
        end
578,622✔
1101
    end
95,296✔
1102
    return b
4,944✔
1103
end
1104
function ldiv!(A::AbstractTriangular, B::AbstractMatrix)
4,606✔
1105
    require_one_based_indexing(A, B)
4,606✔
1106
    nA, mA = size(A)
4,606✔
1107
    n = size(B, 1)
4,606✔
1108
    if nA != n
4,606✔
1109
        throw(DimensionMismatch("second dimension of left hand side A, $mA, and first dimension of right hand side B, $n, must be equal"))
×
1110
    end
1111
    for b in eachcol(B)
9,212✔
1112
        ldiv!(A, b)
38,922✔
1113
    end
73,238✔
1114
    B
4,606✔
1115
end
1116

1117
# in the following transpose and conjugate transpose naive substitution variants,
1118
# accumulating in z rather than b[j,k] significantly improves performance as of Dec 2015
1119
for (t, tfun) in ((:Adjoint, :adjoint), (:Transpose, :transpose))
1120
    @eval begin
1121
        function ldiv!(xA::UpperTriangular{<:Any,<:$t}, b::AbstractVector)
3,905✔
1122
            require_one_based_indexing(xA, b)
3,905✔
1123
            A = parent(parent(xA))
3,905✔
1124
            n = size(A, 1)
3,905✔
1125
            if !(n == length(b))
3,905✔
1126
                throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
24✔
1127
            end
1128
            @inbounds for j in n:-1:1
7,762✔
1129
                z = b[j]
36,182✔
1130
                for i in n:-1:j+1
67,327✔
1131
                    z -= $tfun(A[i,j]) * b[i]
152,785✔
1132
                end
260,159✔
1133
                iszero(A[j,j]) && throw(SingularException(j))
38,004✔
1134
                b[j] = $tfun(A[j,j]) \ z
37,466✔
1135
            end
67,327✔
1136
            return b
3,881✔
1137
        end
1138

1139
        function ldiv!(xA::UnitUpperTriangular{<:Any,<:$t}, b::AbstractVector)
1,793✔
1140
            require_one_based_indexing(xA, b)
1,793✔
1141
            A = parent(parent(xA))
1,793✔
1142
            n = size(A, 1)
1,793✔
1143
            if !(n == length(b))
1,793✔
1144
                throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
36✔
1145
            end
1146
            @inbounds for j in n:-1:1
3,514✔
1147
                z = b[j]
17,540✔
1148
                for i in n:-1:j+1
31,963✔
1149
                    z -= $tfun(A[i,j]) * b[i]
82,531✔
1150
                end
130,691✔
1151
                b[j] = z
17,882✔
1152
            end
31,963✔
1153
            return b
1,757✔
1154
        end
1155

1156
        function ldiv!(xA::LowerTriangular{<:Any,<:$t}, b::AbstractVector)
5,012✔
1157
            require_one_based_indexing(xA, b)
5,012✔
1158
            A = parent(parent(xA))
5,012✔
1159
            n = size(A, 1)
5,012✔
1160
            if !(n == length(b))
5,012✔
1161
                throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
24✔
1162
            end
1163
            @inbounds for j in 1:n
9,976✔
1164
                z = b[j]
47,252✔
1165
                for i in 1:j-1
88,360✔
1166
                    z -= $tfun(A[i,j]) * b[i]
203,596✔
1167
                end
350,126✔
1168
                iszero(A[j,j]) && throw(SingularException(j))
49,074✔
1169
                b[j] = $tfun(A[j,j]) \ z
48,572✔
1170
            end
88,360✔
1171
            return b
4,988✔
1172
        end
1173

1174
        function ldiv!(xA::UnitLowerTriangular{<:Any,<:$t}, b::AbstractVector)
1,194✔
1175
            require_one_based_indexing(xA, b)
1,194✔
1176
            A = parent(parent(xA))
1,194✔
1177
            n = size(A, 1)
1,194✔
1178
            if !(n == length(b))
1,194✔
1179
                throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
36✔
1180
            end
1181
            @inbounds for j in 1:n
2,316✔
1182
                z = b[j]
11,550✔
1183
                for i in 1:j-1
20,582✔
1184
                    z -= $tfun(A[i,j]) * b[i]
53,674✔
1185
                end
82,616✔
1186
                b[j] = z
11,856✔
1187
            end
20,582✔
1188
            return b
1,158✔
1189
        end
1190
    end
1191
end
1192

1193
function rdiv!(A::AbstractMatrix, B::UpperTriangular)
542✔
1194
    require_one_based_indexing(A, B)
542✔
1195
    m, n = size(A)
542✔
1196
    if size(B, 1) != n
542✔
1197
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1198
    end
1199
    @inbounds for i = 1:m
742✔
1200
        for j = 1:n
6,786✔
1201
            Aij = A[i,j]
31,097✔
1202
            for k = 1:j - 1
58,801✔
1203
                Aij -= A[i,k]*B.data[k,j]
127,288✔
1204
            end
226,772✔
1205
            iszero(B.data[j,j]) && throw(SingularException(j))
31,097✔
1206
            A[i,j] = Aij/B.data[j,j]
31,097✔
1207
        end
58,801✔
1208
    end
6,415✔
1209
    A
371✔
1210
end
1211
function rdiv!(A::AbstractMatrix, B::UnitUpperTriangular)
502✔
1212
    require_one_based_indexing(B)
502✔
1213
    m, n = size(A)
502✔
1214
    if size(B, 1) != n
502✔
1215
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1216
    end
1217
    @inbounds for i = 1:m
662✔
1218
        for j = 1:n
5,986✔
1219
            Aij = A[i,j]
27,077✔
1220
            for k = 1:j - 1
51,161✔
1221
                Aij -= A[i,k]*B.data[k,j]
109,008✔
1222
            end
193,932✔
1223
            A[i,j] = Aij
27,077✔
1224
        end
51,161✔
1225
    end
5,655✔
1226
    A
331✔
1227
end
1228
function rdiv!(A::AbstractMatrix, B::LowerTriangular)
542✔
1229
    require_one_based_indexing(A, B)
542✔
1230
    m, n = size(A)
542✔
1231
    if size(B, 1) != n
542✔
1232
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1233
    end
1234
    @inbounds for i = 1:m
742✔
1235
        for j = n:-1:1
6,786✔
1236
            Aij = A[i,j]
31,097✔
1237
            for k = j + 1:n
58,801✔
1238
                Aij -= A[i,k]*B.data[k,j]
127,288✔
1239
            end
226,772✔
1240
            iszero(B.data[j,j]) && throw(SingularException(j))
31,097✔
1241
            A[i,j] = Aij/B.data[j,j]
31,097✔
1242
        end
58,801✔
1243
    end
6,415✔
1244
    A
371✔
1245
end
1246
function rdiv!(A::AbstractMatrix, B::UnitLowerTriangular)
502✔
1247
    require_one_based_indexing(A, B)
502✔
1248
    m, n = size(A)
502✔
1249
    if size(B, 1) != n
502✔
1250
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1251
    end
1252
    @inbounds for i = 1:m
662✔
1253
        for j = n:-1:1
5,986✔
1254
            Aij = A[i,j]
27,077✔
1255
            for k = j + 1:n
51,161✔
1256
                Aij -= A[i,k]*B.data[k,j]
109,008✔
1257
            end
193,932✔
1258
            A[i,j] = Aij
27,077✔
1259
        end
51,161✔
1260
    end
5,655✔
1261
    A
331✔
1262
end
1263

1264
lmul!(A::UpperTriangular,     B::UpperTriangular) = UpperTriangular(lmul!(A, triu!(B.data)))
12✔
1265
lmul!(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(lmul!(A, triu!(B.data)))
12✔
1266
lmul!(A::LowerTriangular,     B::LowerTriangular) = LowerTriangular(lmul!(A, tril!(B.data)))
12✔
1267
lmul!(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(lmul!(A, tril!(B.data)))
12✔
1268

1269
ldiv!(A::UpperTriangular,     B::UpperTriangular) = UpperTriangular(ldiv!(A, triu!(B.data)))
18✔
1270
ldiv!(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(ldiv!(A, triu!(B.data)))
18✔
1271
ldiv!(A::LowerTriangular,     B::LowerTriangular) = LowerTriangular(ldiv!(A, tril!(B.data)))
18✔
1272
ldiv!(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(ldiv!(A, tril!(B.data)))
18✔
1273

1274
rdiv!(A::UpperTriangular, B::UpperTriangular)     = UpperTriangular(rdiv!(triu!(A.data), B))
1,512✔
1275
rdiv!(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(rdiv!(triu!(A.data), B))
18✔
1276
rdiv!(A::LowerTriangular, B::LowerTriangular)     = LowerTriangular(rdiv!(tril!(A.data), B))
18✔
1277
rdiv!(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(rdiv!(tril!(A.data), B))
18✔
1278

1279
rmul!(A::UpperTriangular, B::UpperTriangular)     = UpperTriangular(rmul!(triu!(A.data), B))
12✔
1280
rmul!(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(rmul!(triu!(A.data), B))
12✔
1281
rmul!(A::LowerTriangular, B::LowerTriangular)     = LowerTriangular(rmul!(tril!(A.data), B))
12✔
1282
rmul!(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(rmul!(tril!(A.data), B))
12✔
1283

1284
# Promotion
1285
## Promotion methods in matmul don't apply to triangular multiplication since
1286
## it is inplace. Hence we have to make very similar definitions, but without
1287
## allocation of a result array. For multiplication and unit diagonal division
1288
## the element type doesn't have to be stable under division whereas that is
1289
## necessary in the general triangular solve problem.
1290

1291
## Some Triangular-Triangular cases. We might want to write tailored methods
1292
## for these cases, but I'm not sure it is worth it.
1293

1294
for (f, f2!) in ((:*, :lmul!), (:\, :ldiv!))
1295
    @eval begin
1296
        function ($f)(A::LowerTriangular, B::LowerTriangular)
691✔
1297
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
691✔
1298
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1299
            BB = copy_similar(B, TAB)
691✔
1300
            return LowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
691✔
1301
        end
1302

1303
        function $(f)(A::UnitLowerTriangular, B::LowerTriangular)
626✔
1304
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
626✔
1305
                         (*)(zero(eltype(A)), zero(eltype(B))))
1306
             BB = copy_similar(B, TAB)
626✔
1307
            return LowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
626✔
1308
        end
1309

1310
        function $(f)(A::LowerTriangular, B::UnitLowerTriangular)
624✔
1311
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
624✔
1312
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1313
             BB = copy_similar(B, TAB)
624✔
1314
            return LowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
624✔
1315
        end
1316

1317
        function $(f)(A::UnitLowerTriangular, B::UnitLowerTriangular)
615✔
1318
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
615✔
1319
                         (*)(zero(eltype(A)), zero(eltype(B))))
1320
             BB = copy_similar(B, TAB)
615✔
1321
            return UnitLowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
615✔
1322
        end
1323

1324
        function ($f)(A::UpperTriangular, B::UpperTriangular)
2,427✔
1325
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
2,427✔
1326
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1327
            BB = copy_similar(B, TAB)
2,427✔
1328
            return UpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
2,427✔
1329
        end
1330

1331
        function ($f)(A::UnitUpperTriangular, B::UpperTriangular)
626✔
1332
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
626✔
1333
                         (*)(zero(eltype(A)), zero(eltype(B))))
1334
            BB = copy_similar(B, TAB)
626✔
1335
            return UpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
626✔
1336
        end
1337

1338
        function ($f)(A::UpperTriangular, B::UnitUpperTriangular)
624✔
1339
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
624✔
1340
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1341
            BB = copy_similar(B, TAB)
624✔
1342
            return UpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
624✔
1343
        end
1344

1345
        function ($f)(A::UnitUpperTriangular, B::UnitUpperTriangular)
620✔
1346
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
620✔
1347
                         (*)(zero(eltype(A)), zero(eltype(B))))
1348
            BB = copy_similar(B, TAB)
620✔
1349
            return UnitUpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
620✔
1350
        end
1351
    end
1352
end
1353

1354
function (/)(A::LowerTriangular, B::LowerTriangular)
123✔
1355
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
123✔
1356
                 (/)(zero(eltype(A)), one(eltype(B))))
1357
    AA = copy_similar(A, TAB)
123✔
1358
    return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
123✔
1359
end
1360
function (/)(A::UnitLowerTriangular, B::LowerTriangular)
98✔
1361
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
98✔
1362
                 (/)(zero(eltype(A)), one(eltype(B))))
1363
    AA = copy_similar(A, TAB)
98✔
1364
    return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
98✔
1365
end
1366
function (/)(A::LowerTriangular, B::UnitLowerTriangular)
116✔
1367
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
116✔
1368
                 (/)(zero(eltype(A)), one(eltype(B))))
1369
    AA = copy_similar(A, TAB)
116✔
1370
    return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
116✔
1371
end
1372
function (/)(A::UnitLowerTriangular, B::UnitLowerTriangular)
105✔
1373
    TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
105✔
1374
                 (*)(zero(eltype(A)), zero(eltype(B))))
1375
    AA = copy_similar(A, TAB)
105✔
1376
    return UnitLowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
105✔
1377
end
1378
function (/)(A::UpperTriangular, B::UpperTriangular)
161✔
1379
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
161✔
1380
                 (/)(zero(eltype(A)), one(eltype(B))))
1381
    AA = copy_similar(A, TAB)
161✔
1382
    return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
161✔
1383
end
1384
function (/)(A::UnitUpperTriangular, B::UpperTriangular)
98✔
1385
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
98✔
1386
                 (/)(zero(eltype(A)), one(eltype(B))))
1387
    AA = copy_similar(A, TAB)
98✔
1388
    return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
98✔
1389
end
1390
function (/)(A::UpperTriangular, B::UnitUpperTriangular)
116✔
1391
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
116✔
1392
                 (/)(zero(eltype(A)), one(eltype(B))))
1393
    AA = copy_similar(A, TAB)
116✔
1394
    return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
116✔
1395
end
1396
function (/)(A::UnitUpperTriangular, B::UnitUpperTriangular)
105✔
1397
    TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
105✔
1398
                 (*)(zero(eltype(A)), zero(eltype(B))))
1399
    AA = copy_similar(A, TAB)
105✔
1400
    return UnitUpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
105✔
1401
end
1402

1403
_inner_type_promotion(A,B) = promote_type(eltype(A), eltype(B), typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))))
19,816✔
1404
## The general promotion methods
1405
function *(A::AbstractTriangular, B::AbstractTriangular)
3,643✔
1406
    TAB = _inner_type_promotion(A,B)
3,643✔
1407
    BB = copy_similar(B, TAB)
3,649✔
1408
    lmul!(convert(AbstractArray{TAB}, A), BB)
3,643✔
1409
end
1410

1411
for mat in (:AbstractVector, :AbstractMatrix)
1412
    ### Multiplication with triangle to the left and hence rhs cannot be transposed.
1413
    @eval function *(A::AbstractTriangular, B::$mat)
6,142✔
1414
        require_one_based_indexing(B)
6,142✔
1415
        TAB = _inner_type_promotion(A,B)
6,142✔
1416
        BB = copy_similar(B, TAB)
8,610✔
1417
        lmul!(convert(AbstractArray{TAB}, A), BB)
6,142✔
1418
    end
1419
    ### Left division with triangle to the left hence rhs cannot be transposed. No quotients.
1420
    @eval function \(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::$mat)
3,677✔
1421
        require_one_based_indexing(B)
3,677✔
1422
        TAB = _inner_type_promotion(A,B)
3,677✔
1423
        BB = copy_similar(B, TAB)
5,183✔
1424
        ldiv!(convert(AbstractArray{TAB}, A), BB)
3,677✔
1425
    end
1426
    ### Left division with triangle to the left hence rhs cannot be transposed. Quotients.
1427
    @eval function \(A::Union{UpperTriangular,LowerTriangular}, B::$mat)
9,582✔
1428
        require_one_based_indexing(B)
9,582✔
1429
        TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A)))
9,582✔
1430
        BB = copy_similar(B, TAB)
12,546✔
1431
        ldiv!(convert(AbstractArray{TAB}, A), BB)
9,582✔
1432
    end
1433
    ### Right division with triangle to the right hence lhs cannot be transposed. No quotients.
1434
    @eval function /(A::$mat, B::Union{UnitUpperTriangular, UnitLowerTriangular})
1,993✔
1435
        require_one_based_indexing(A)
1,993✔
1436
        TAB = _inner_type_promotion(A,B)
1,993✔
1437
        AA = copy_similar(A, TAB)
2,789✔
1438
        rdiv!(AA, convert(AbstractArray{TAB}, B))
1,993✔
1439
    end
1440
    ### Right division with triangle to the right hence lhs cannot be transposed. Quotients.
1441
    @eval function /(A::$mat, B::Union{UpperTriangular,LowerTriangular})
2,017✔
1442
        require_one_based_indexing(A)
2,017✔
1443
        TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A)))
2,017✔
1444
        AA = copy_similar(A, TAB)
2,813✔
1445
        rdiv!(AA, convert(AbstractArray{TAB}, B))
2,017✔
1446
    end
1447
end
1448
### Multiplication with triangle to the right and hence lhs cannot be transposed.
1449
# Only for AbstractMatrix, hence outside the above loop.
1450
function *(A::AbstractMatrix, B::AbstractTriangular)
4,361✔
1451
    require_one_based_indexing(A)
4,361✔
1452
    TAB = _inner_type_promotion(A,B)
4,361✔
1453
    AA = copy_similar(A, TAB)
5,983✔
1454
    rmul!(AA, convert(AbstractArray{TAB}, B))
4,361✔
1455
end
1456
# ambiguity resolution with definitions in matmul.jl
1457
*(v::AdjointAbsVec, A::AbstractTriangular) = adjoint(adjoint(A) * v.parent)
404✔
1458
*(v::TransposeAbsVec, A::AbstractTriangular) = transpose(transpose(A) * v.parent)
344✔
1459

1460
# Complex matrix power for upper triangular factor, see:
1461
#   Higham and Lin, "A Schur-Padé algorithm for fractional powers of a Matrix",
1462
#     SIAM J. Matrix Anal. & Appl., 32 (3), (2011) 1056–1078.
1463
#   Higham and Lin, "An improved Schur-Padé algorithm for fractional powers of
1464
#     a matrix and their Fréchet derivatives", SIAM. J. Matrix Anal. & Appl.,
1465
#     34(3), (2013) 1341–1360.
1466
function powm!(A0::UpperTriangular{<:BlasFloat}, p::Real)
60✔
1467
    if abs(p) >= 1
60✔
1468
        throw(ArgumentError("p must be a real number in (-1,1), got $p"))
2✔
1469
    end
1470

1471
    normA0 = opnorm(A0, 1)
58✔
1472
    rmul!(A0, 1/normA0)
58✔
1473

1474
    theta = [1.53e-5, 2.25e-3, 1.92e-2, 6.08e-2, 1.25e-1, 2.03e-1, 2.84e-1]
406✔
1475
    n = checksquare(A0)
58✔
1476

1477
    A, m, s = invsquaring(A0, theta)
58✔
1478
    A = I - A
58✔
1479

1480
    # Compute accurate diagonal of I - T
1481
    sqrt_diag!(A0, A, s)
58✔
1482
    for i = 1:n
116✔
1483
        A[i, i] = -A[i, i]
202✔
1484
    end
346✔
1485
    # Compute the Padé approximant
1486
    c = 0.5 * (p - m) / (2 * m - 1)
58✔
1487
    triu!(A)
58✔
1488
    S = c * A
58✔
1489
    Stmp = similar(S)
58✔
1490
    for j = m-1:-1:1
116✔
1491
        j4 = 4 * j
248✔
1492
        c = (-p - j) / (j4 + 2)
248✔
1493
        for i = 1:n
496✔
1494
            @inbounds S[i, i] = S[i, i] + 1
884✔
1495
        end
1,520✔
1496
        copyto!(Stmp, S)
248✔
1497
        mul!(S, A, c)
884✔
1498
        ldiv!(Stmp, S.data)
248✔
1499

1500
        c = (p - j) / (j4 - 2)
248✔
1501
        for i = 1:n
496✔
1502
            @inbounds S[i, i] = S[i, i] + 1
884✔
1503
        end
1,520✔
1504
        copyto!(Stmp, S)
248✔
1505
        mul!(S, A, c)
884✔
1506
        ldiv!(Stmp, S.data)
248✔
1507
    end
438✔
1508
    for i = 1:n
116✔
1509
        S[i, i] = S[i, i] + 1
202✔
1510
    end
346✔
1511
    copyto!(Stmp, S)
58✔
1512
    mul!(S, A, -p)
202✔
1513
    ldiv!(Stmp, S.data)
58✔
1514
    for i = 1:n
116✔
1515
        @inbounds S[i, i] = S[i, i] + 1
202✔
1516
    end
346✔
1517

1518
    blockpower!(A0, S, p/(2^s))
58✔
1519
    for m = 1:s
116✔
1520
        mul!(Stmp.data, S, S)
234✔
1521
        copyto!(S, Stmp)
234✔
1522
        blockpower!(A0, S, p/(2^(s-m)))
234✔
1523
    end
410✔
1524
    rmul!(S, normA0^p)
58✔
1525
    return S
58✔
1526
end
1527
powm(A::LowerTriangular, p::Real) = copy(transpose(powm!(copy(transpose(A)), p::Real)))
2✔
1528

1529
# Complex matrix logarithm for the upper triangular factor, see:
1530
#   Al-Mohy and Higham, "Improved inverse scaling and squaring algorithms for
1531
#     the matrix logarithm", SIAM J. Sci. Comput., 34(4), (2012), pp. C153–C169.
1532
#   Al-Mohy, Higham and Relton, "Computing the Frechet derivative of the matrix
1533
#     logarithm and estimating the condition number", SIAM J. Sci. Comput.,
1534
#     35(4), (2013), C394–C410.
1535
#
1536
# Based on the code available at http://eprints.ma.man.ac.uk/1851/02/logm.zip,
1537
# Copyright (c) 2011, Awad H. Al-Mohy and Nicholas J. Higham
1538
# Julia version relicensed with permission from original authors
1539
log(A::UpperTriangular{T}) where {T<:BlasFloat} = log_quasitriu(A)
235✔
1540
log(A::UnitUpperTriangular{T}) where {T<:BlasFloat} = log_quasitriu(A)
26✔
1541
log(A::LowerTriangular) = copy(transpose(log(copy(transpose(A)))))
4✔
1542
log(A::UnitLowerTriangular) = copy(transpose(log(copy(transpose(A)))))
4✔
1543

1544
function log_quasitriu(A0::AbstractMatrix{T}) where T<:BlasFloat
274✔
1545
    # allocate real A if log(A) will be real and complex A otherwise
1546
    n = checksquare(A0)
274✔
1547
    if isreal(A0) && (!istriu(A0) || !any(x -> real(x) < zero(real(T)), diag(A0)))
835✔
1548
        A = T <: Complex ? real(A0) : copy(A0)
91✔
1549
    else
1550
        A = T <: Complex ? copy(A0) : complex(A0)
183✔
1551
    end
1552
    if A0 isa UnitUpperTriangular
274✔
1553
        A = UpperTriangular(parent(A))
26✔
1554
        @inbounds for i in 1:n
52✔
1555
            A[i,i] = 1
234✔
1556
        end
442✔
1557
    end
1558
    Y0 = _log_quasitriu!(A0, A)
365✔
1559
    # return complex result for complex input
1560
    Y = T <: Complex ? complex(Y0) : Y0
300✔
1561

1562
    if A0 isa UpperTriangular || A0 isa UnitUpperTriangular
274✔
1563
        return UpperTriangular(Y)
261✔
1564
    else
1565
        return Y
13✔
1566
    end
1567
end
1568
# type-stable implementation of log_quasitriu
1569
# A is a copy of A0 that is overwritten while computing the result. It has the same eltype
1570
# as the result.
1571
function _log_quasitriu!(A0, A)
274✔
1572
    # Find Padé degree m and s while replacing A with A^(1/2^s)
1573
    m, s = _find_params_log_quasitriu!(A)
274✔
1574

1575
    # Compute accurate superdiagonal of A
1576
    _pow_superdiag_quasitriu!(A, A0, 0.5^s)
541✔
1577

1578
    # Compute accurate block diagonal of A
1579
    _sqrt_pow_diag_quasitriu!(A, A0, s)
274✔
1580

1581
    # Get the Gauss-Legendre quadrature points and weights
1582
    R = zeros(Float64, m, m)
9,183✔
1583
    for i = 1:m - 1
539✔
1584
        R[i,i+1] = i / sqrt((2 * i)^2 - 1)
1,281✔
1585
        R[i+1,i] = R[i,i+1]
1,281✔
1586
    end
2,297✔
1587
    x,V = eigen(R)
548✔
1588
    w = Vector{Float64}(undef, m)
274✔
1589
    for i = 1:m
548✔
1590
        x[i] = (x[i] + 1) / 2
3,110✔
1591
        w[i] = V[1,i]^2
1,555✔
1592
    end
2,836✔
1593

1594
    # Compute the Padé approximation
1595
    t = eltype(A)
274✔
1596
    n = size(A, 1)
274✔
1597
    Y = zeros(t, n, n)
6,588✔
1598
    B = similar(A)
274✔
1599
    for k = 1:m
548✔
1600
        B .= t(x[k]) .* A
1,616✔
1601
        @inbounds for i in 1:n
3,110✔
1602
            B[i,i] += 1
6,508✔
1603
        end
11,461✔
1604
        Y .+= t(w[k]) .* rdiv_quasitriu!(A, B)
3,110✔
1605
    end
2,836✔
1606

1607
    # Scale back
1608
    lmul!(2.0^s, Y)
541✔
1609

1610
    # Compute accurate diagonal and superdiagonal of log(A)
1611
    _log_diag_quasitriu!(Y, A0)
274✔
1612

1613
    return Y
274✔
1614
end
1615

1616
# Auxiliary functions for matrix logarithm and matrix power
1617

1618
# Find Padé degree m and s while replacing A with A^(1/2^s)
1619
#   Al-Mohy and Higham, "Improved inverse scaling and squaring algorithms for
1620
#     the matrix logarithm", SIAM J. Sci. Comput., 34(4), (2012), pp. C153–C169.
1621
#   from Algorithm 4.1
1622
function _find_params_log_quasitriu!(A)
274✔
1623
    maxsqrt = 100
274✔
1624
    theta = [1.586970738772063e-005,
1,918✔
1625
         2.313807884242979e-003,
1626
         1.938179313533253e-002,
1627
         6.209171588994762e-002,
1628
         1.276404810806775e-001,
1629
         2.060962623452836e-001,
1630
         2.879093714241194e-001]
1631
    tmax = size(theta, 1)
274✔
1632
    n = size(A, 1)
274✔
1633
    p = 0
274✔
1634
    m = 0
274✔
1635

1636
    # Find s0, the smallest s such that the ρ(triu(A)^(1/2^s) - I) ≤ theta[tmax], where ρ(X)
1637
    # is the spectral radius of X
1638
    d = complex.(@view(A[diagind(A)]))
287✔
1639
    dm1 = d .- 1
548✔
1640
    s = 0
274✔
1641
    while norm(dm1, Inf) > theta[tmax] && s < maxsqrt
1,281✔
1642
        d .= sqrt.(d)
1,007✔
1643
        dm1 .= d .- 1
2,014✔
1644
        s = s + 1
1,007✔
1645
    end
1,007✔
1646
    s0 = s
274✔
1647

1648
    # Compute repeated roots
1649
    for k = 1:min(s, maxsqrt)
514✔
1650
        _sqrt_quasitriu!(A isa UpperTriangular ? parent(A) : A, A)
1,007✔
1651
    end
1,774✔
1652

1653
    # these three never needed at the same time, so reuse the same temporary
1654
    AmI = AmI4 = AmI5 = A - I
274✔
1655
    AmI2 = AmI * AmI
274✔
1656
    AmI3 = AmI2 * AmI
274✔
1657
    d2 = sqrt(opnorm(AmI2, 1))
274✔
1658
    d3 = cbrt(opnorm(AmI3, 1))
274✔
1659
    alpha2 = max(d2, d3)
274✔
1660
    foundm = false
274✔
1661
    if alpha2 <= theta[2]
274✔
1662
        m = alpha2 <= theta[1] ? 1 : 2
9✔
1663
        foundm = true
9✔
1664
    end
1665

1666
    while !foundm
618✔
1667
        more_sqrt = false
609✔
1668
        mul!(AmI4, AmI2, AmI2)
609✔
1669
        d4 = opnorm(AmI4, 1)^(1/4)
609✔
1670
        alpha3 = max(d3, d4)
609✔
1671
        if alpha3 <= theta[tmax]
609✔
1672
            local j
×
1673
            for outer j = 3:tmax
688✔
1674
                if alpha3 <= theta[j]
1,414✔
1675
                    break
344✔
1676
                end
1677
            end
1,070✔
1678
            if j <= 6
344✔
1679
                m = j
206✔
1680
                break
206✔
1681
            elseif alpha3 / 2 <= theta[5] && p < 2
138✔
1682
                more_sqrt = true
103✔
1683
                p = p + 1
103✔
1684
           end
1685
        end
1686

1687
        if !more_sqrt
403✔
1688
            mul!(AmI5, AmI3, AmI2)
300✔
1689
            d5 = opnorm(AmI5, 1)^(1/5)
300✔
1690
            alpha4 = max(d4, d5)
300✔
1691
            eta = min(alpha3, alpha4)
300✔
1692
            if eta <= theta[tmax]
300✔
1693
                j = 0
58✔
1694
                for outer j = 6:tmax
116✔
1695
                    if eta <= theta[j]
113✔
1696
                        m = j
58✔
1697
                        break
58✔
1698
                    end
1699
                end
55✔
1700
                break
58✔
1701
            end
1702
        end
1703

1704
        if s == maxsqrt
345✔
1705
            m = tmax
1✔
1706
            break
1✔
1707
        end
1708
        _sqrt_quasitriu!(A isa UpperTriangular ? parent(A) : A, A)
344✔
1709
        copyto!(AmI, A)
344✔
1710
        for i in 1:n
688✔
1711
            @inbounds AmI[i,i] -= 1
1,726✔
1712
        end
3,108✔
1713
        mul!(AmI2, AmI, AmI)
344✔
1714
        mul!(AmI3, AmI2, AmI)
344✔
1715
        d3 = cbrt(opnorm(AmI3, 1))
344✔
1716
        s = s + 1
344✔
1717
    end
344✔
1718
    return m, s
274✔
1719
end
1720

1721
# Compute accurate diagonal of A = A0^s - I
1722
function sqrt_diag!(A0::UpperTriangular, A::UpperTriangular, s)
58✔
1723
    n = checksquare(A0)
58✔
1724
    T = eltype(A)
58✔
1725
    @inbounds for i = 1:n
116✔
1726
        a = complex(A0[i,i])
202✔
1727
        A[i,i] = _sqrt_pow(a, s)
202✔
1728
    end
202✔
1729
end
1730
# Compute accurate block diagonal of A = A0^s - I for upper quasi-triangular A0 produced
1731
# by the Schur decomposition. Diagonal is made of 1x1 and 2x2 blocks.
1732
# 2x2 blocks are real with non-negative conjugate pair eigenvalues
1733
function _sqrt_pow_diag_quasitriu!(A, A0, s)
274✔
1734
    n = checksquare(A0)
274✔
1735
    t = typeof(sqrt(zero(eltype(A))))
274✔
1736
    i = 1
274✔
1737
    @inbounds while i < n
274✔
1738
        if iszero(A0[i+1,i])  # 1x1 block
1,675✔
1739
            A[i,i] = _sqrt_pow(t(A0[i,i]), s)
833✔
1740
            i += 1
833✔
1741
        else  # real 2x2 block
1742
            @views _sqrt_pow_diag_block_2x2!(A[i:i+1,i:i+1], A0[i:i+1,i:i+1], s)
17✔
1743
            i += 2
17✔
1744
        end
1745
    end
850✔
1746
    if i == n  # last block is 1x1
274✔
1747
        @inbounds A[n,n] = _sqrt_pow(t(A0[n,n]), s)
267✔
1748
    end
1749
    return A
274✔
1750
end
1751
# compute a^(1/2^s)-1
1752
#   Al-Mohy, "A more accurate Briggs method for the logarithm",
1753
#      Numer. Algorithms, 59, (2012), 393–402.
1754
#   Algorithm 2
1755
function _sqrt_pow(a::Number, s)
1,302✔
1756
    T = typeof(sqrt(zero(a)))
1,302✔
1757
    s == 0 && return T(a) - 1
1,302✔
1758
    s0 = s
1,275✔
1759
    if imag(a) >= 0 && real(a) <= 0 && !iszero(a)  # angle(a) ≥ π / 2
1,275✔
1760
        a = sqrt(a)
89✔
1761
        s0 = s - 1
89✔
1762
    end
1763
    z0 = a - 1
1,275✔
1764
    a = sqrt(a)
1,275✔
1765
    r = 1 + a
1,275✔
1766
    for j = 1:s0-1
2,534✔
1767
        a = sqrt(a)
3,632✔
1768
        r = r * (1 + a)
3,632✔
1769
    end
6,005✔
1770
    return z0 / r
1,275✔
1771
end
1772
# compute A0 = A^(1/2^s)-I for 2x2 real matrices A and A0
1773
# A has non-negative conjugate pair eigenvalues
1774
# "Improved Inverse Scaling and Squaring Algorithms for the Matrix Logarithm"
1775
# SIAM J. Sci. Comput., 34(4), (2012) C153–C169. doi: 10.1137/110852553
1776
# Algorithm 5.1
1777
Base.@propagate_inbounds function _sqrt_pow_diag_block_2x2!(A, A0, s)
17✔
1778
    _sqrt_real_2x2!(A, A0)
17✔
1779
    if isone(s)
17✔
1780
        A[1,1] -= 1
×
1781
        A[2,2] -= 1
×
1782
    else
1783
        # Z = A - I
1784
        z11, z21, z12, z22 = A[1,1] - 1, A[2,1], A[1,2], A[2,2] - 1
17✔
1785
        # A = sqrt(A)
1786
        _sqrt_real_2x2!(A, A)
17✔
1787
        # P = A + I
1788
        p11, p21, p12, p22 = A[1,1] + 1, A[2,1], A[1,2], A[2,2] + 1
17✔
1789
        for i in 1:(s - 2)
34✔
1790
            # A = sqrt(A)
1791
            _sqrt_real_2x2!(A, A)
423✔
1792
            a11, a21, a12, a22 = A[1,1], A[2,1], A[1,2], A[2,2]
423✔
1793
            # P += P * A
1794
            r11 = p11*(1 + a11) + p12*a21
423✔
1795
            r22 = p21*a12 + p22*(1 + a22)
423✔
1796
            p21 = p21*(1 + a11) + p22*a21
423✔
1797
            p12 = p11*a12 + p12*(1 + a22)
423✔
1798
            p11 = r11
423✔
1799
            p22 = r22
423✔
1800
        end
829✔
1801
        # A = Z / P
1802
        c = inv(p11*p22 - p21*p12)
17✔
1803
        A[1,1] = (p22*z11 - p21*z12) * c
17✔
1804
        A[2,1] = (p22*z21 - p21*z22) * c
17✔
1805
        A[1,2] = (p11*z12 - p12*z11) * c
17✔
1806
        A[2,2] = (p11*z22 - p12*z21) * c
17✔
1807
    end
1808
    return A
17✔
1809
end
1810
# Compute accurate superdiagonal of A = A0^s - I for upper quasi-triangular A0 produced
1811
# by a Schur decomposition.
1812
# Higham and Lin, "A Schur–Padé Algorithm for Fractional Powers of a Matrix"
1813
# SIAM J. Matrix Anal. Appl., 32(3), (2011), 1056–1078.
1814
# Equation 5.6
1815
# see also blockpower for when A0 is upper triangular
1816
function _pow_superdiag_quasitriu!(A, A0, p)
274✔
1817
    n = checksquare(A0)
274✔
1818
    t = eltype(A)
274✔
1819
    k = 1
274✔
1820
    @inbounds while k < n
274✔
1821
        if !iszero(A[k+1,k])
1,668✔
1822
            k += 2
10✔
1823
            continue
10✔
1824
        end
1825
        if !(k == n - 1 || iszero(A[k+2,k+1]))
1,408✔
1826
            k += 3
7✔
1827
            continue
7✔
1828
        end
1829
        Ak = t(A0[k,k])
986✔
1830
        Akp1 = t(A0[k+1,k+1])
986✔
1831

1832
        Akp = Ak^p
826✔
1833
        Akp1p = Akp1^p
826✔
1834

1835
        if Ak == Akp1
826✔
1836
            A[k,k+1] = p * A0[k,k+1] * Ak^(p-1)
285✔
1837
        elseif 2 * abs(Ak) < abs(Akp1) || 2 * abs(Akp1) < abs(Ak) || iszero(Akp1 + Ak)
1,072✔
1838
            A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
251✔
1839
        else
1840
            logAk = log(Ak)
290✔
1841
            logAkp1 = log(Akp1)
290✔
1842
            z = (Akp1 - Ak)/(Akp1 + Ak)
290✔
1843
            if abs(z) > 1
358✔
1844
                A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
25✔
1845
            else
1846
                w = atanh(z) + im * pi * (unw(logAkp1-logAk) - unw(log1p(z)-log1p(-z)))
265✔
1847
                dd = 2 * exp(p*(logAk+logAkp1)/2) * sinh(p*w) / (Akp1 - Ak);
437✔
1848
                A[k,k+1] = A0[k,k+1] * dd
265✔
1849
            end
1850
        end
1851
        k += 1
826✔
1852
    end
1,117✔
1853
end
1854

1855
# Compute accurate block diagonal and superdiagonal of A = log(A0) for upper
1856
# quasi-triangular A0 produced by the Schur decomposition.
1857
function _log_diag_quasitriu!(A, A0)
274✔
1858
    n = checksquare(A0)
274✔
1859
    t = eltype(A)
274✔
1860
    k = 1
274✔
1861
    @inbounds while k < n
274✔
1862
        if iszero(A0[k+1,k])  # 1x1 block
1,228✔
1863
            Ak = t(A0[k,k])
709✔
1864
            logAk = log(Ak)
609✔
1865
            A[k,k] = logAk
609✔
1866
            if k < n - 2 && iszero(A0[k+2,k+1])
832✔
1867
                Akp1 = t(A0[k+1,k+1])
284✔
1868
                logAkp1 = log(Akp1)
224✔
1869
                A[k+1,k+1] = logAkp1
224✔
1870
                if Ak == Akp1
224✔
1871
                    A[k,k+1] = A0[k,k+1] / Ak
103✔
1872
                elseif 2 * abs(Ak) < abs(Akp1) || 2 * abs(Akp1) < abs(Ak) || iszero(Akp1 + Ak)
242✔
1873
                    A[k,k+1] = A0[k,k+1] * (logAkp1 - logAk) / (Akp1 - Ak)
49✔
1874
                else
1875
                    z = (Akp1 - Ak)/(Akp1 + Ak)
72✔
1876
                    if abs(z) > 1
82✔
1877
                        A[k,k+1] = A0[k,k+1] * (logAkp1 - logAk) / (Akp1 - Ak)
8✔
1878
                    else
1879
                        w = atanh(z) + im * pi * (unw(logAkp1-logAk) - unw(log1p(z)-log1p(-z)))
64✔
1880
                        A[k,k+1] = 2 * A0[k,k+1] * w / (Akp1 - Ak)
64✔
1881
                    end
1882
                end
1883
                k += 2
224✔
1884
            else
1885
                k += 1
994✔
1886
            end
1887
        else  # real 2x2 block
1888
            @views _log_diag_block_2x2!(A[k:k+1,k:k+1], A0[k:k+1,k:k+1])
17✔
1889
            k += 2
17✔
1890
        end
1891
    end
626✔
1892
    if k == n  # last 1x1 block
274✔
1893
        @inbounds A[n,n] = log(t(A0[n,n]))
287✔
1894
    end
1895
    return A
274✔
1896
end
1897
# compute A0 = log(A) for 2x2 real matrices A and A0, where A0 is a diagonal 2x2 block
1898
# produced by real Schur decomposition.
1899
# Al-Mohy, Higham and Relton, "Computing the Frechet derivative of the matrix
1900
# logarithm and estimating the condition number", SIAM J. Sci. Comput.,
1901
# 35(4), (2013), C394–C410.
1902
# Eq. 6.1
1903
Base.@propagate_inbounds function _log_diag_block_2x2!(A, A0)
17✔
1904
    a, b, c = A0[1,1], A0[1,2], A0[2,1]
17✔
1905
    # avoid underflow/overflow for large/small b and c
1906
    s = sqrt(abs(b)) * sqrt(abs(c))
17✔
1907
    θ = atan(s, a)
17✔
1908
    t = θ / s
17✔
1909
    au = abs(a)
17✔
1910
    if au > s
17✔
1911
        a1 = log1p((s / au)^2) / 2 + log(au)
7✔
1912
    else
1913
        a1 = log1p((au / s)^2) / 2 + log(s)
10✔
1914
    end
1915
    A[1,1] = a1
17✔
1916
    A[2,1] = c*t
17✔
1917
    A[1,2] = b*t
17✔
1918
    A[2,2] = a1
17✔
1919
    return A
17✔
1920
end
1921

1922
# Used only by powm at the moment
1923
# Repeatedly compute the square roots of A so that in the end its
1924
# eigenvalues are close enough to the positive real line
1925
function invsquaring(A0::UpperTriangular, theta)
58✔
1926
    require_one_based_indexing(theta)
58✔
1927
    # assumes theta is in ascending order
1928
    maxsqrt = 100
58✔
1929
    tmax = size(theta, 1)
58✔
1930
    n = checksquare(A0)
58✔
1931
    A = complex(copy(A0))
58✔
1932
    p = 0
58✔
1933
    m = 0
58✔
1934

1935
    # Compute repeated roots
1936
    d = complex(diag(A))
58✔
1937
    dm1 = d .- 1
116✔
1938
    s = 0
58✔
1939
    while norm(dm1, Inf) > theta[tmax] && s < maxsqrt
206✔
1940
        d .= sqrt.(d)
148✔
1941
        dm1 .= d .- 1
296✔
1942
        s = s + 1
148✔
1943
    end
148✔
1944
    s0 = s
58✔
1945
    for k = 1:min(s, maxsqrt)
102✔
1946
        A = sqrt(A)
148✔
1947
    end
252✔
1948

1949
    AmI = A - I
58✔
1950
    d2 = sqrt(opnorm(AmI^2, 1))
58✔
1951
    d3 = cbrt(opnorm(AmI^3, 1))
58✔
1952
    alpha2 = max(d2, d3)
58✔
1953
    foundm = false
58✔
1954
    if alpha2 <= theta[2]
58✔
1955
        m = alpha2 <= theta[1] ? 1 : 2
×
1956
        foundm = true
×
1957
    end
1958

1959
    while !foundm
186✔
1960
        more = false
186✔
1961
        if s > s0
186✔
1962
            d3 = cbrt(opnorm(AmI^3, 1))
114✔
1963
        end
1964
        d4 = opnorm(AmI^4, 1)^(1/4)
186✔
1965
        alpha3 = max(d3, d4)
186✔
1966
        if alpha3 <= theta[tmax]
186✔
1967
            local j
×
1968
            for outer j = 3:tmax
284✔
1969
                if alpha3 <= theta[j]
610✔
1970
                    break
142✔
1971
                elseif alpha3 / 2 <= theta[5] && p < 2
468✔
1972
                    more = true
116✔
1973
                    p = p + 1
116✔
1974
                end
1975
            end
468✔
1976
            if j <= 6
142✔
1977
                m = j
58✔
1978
                foundm = true
58✔
1979
                break
58✔
1980
            elseif alpha3 / 2 <= theta[5] && p < 2
84✔
1981
                more = true
×
1982
                p = p + 1
×
1983
           end
1984
        end
1985

1986
        if !more
128✔
1987
            d5 = opnorm(AmI^5, 1)^(1/5)
86✔
1988
            alpha4 = max(d4, d5)
86✔
1989
            eta = min(alpha3, alpha4)
86✔
1990
            if eta <= theta[tmax]
86✔
1991
                j = 0
56✔
1992
                for outer j = 6:tmax
112✔
1993
                    if eta <= theta[j]
56✔
1994
                        m = j
14✔
1995
                        break
14✔
1996
                    end
1997
                    break
42✔
1998
                end
×
1999
            end
2000
            if s == maxsqrt
86✔
2001
                m = tmax
×
2002
                break
×
2003
            end
2004
            A = sqrt(A)
86✔
2005
            AmI = A - I
86✔
2006
            s = s + 1
86✔
2007
        end
2008
    end
128✔
2009

2010
    # Compute accurate superdiagonal of T
2011
    p = 1 / 2^s
58✔
2012
    A = complex(A)
58✔
2013
    blockpower!(A, A0, p)
58✔
2014
    return A,m,s
58✔
2015
end
2016

2017
# Compute accurate diagonal and superdiagonal of A = A0^p
2018
function blockpower!(A::UpperTriangular, A0::UpperTriangular, p)
350✔
2019
    n = checksquare(A0)
350✔
2020
    @inbounds for k = 1:n-1
700✔
2021
        Ak = complex(A0[k,k])
924✔
2022
        Akp1 = complex(A0[k+1,k+1])
924✔
2023

2024
        Akp = Ak^p
924✔
2025
        Akp1p = Akp1^p
924✔
2026

2027
        A[k,k] = Akp
924✔
2028
        A[k+1,k+1] = Akp1p
924✔
2029

2030
        if Ak == Akp1
924✔
2031
            A[k,k+1] = p * A0[k,k+1] * Ak^(p-1)
98✔
2032
        elseif 2 * abs(Ak) < abs(Akp1) || 2 * abs(Akp1) < abs(Ak) || iszero(Akp1 + Ak)
1,610✔
2033
            A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
98✔
2034
        else
2035
            logAk = log(Ak)
728✔
2036
            logAkp1 = log(Akp1)
728✔
2037
            z = (Akp1 - Ak)/(Akp1 + Ak)
728✔
2038
            if abs(z) > 1
728✔
2039
                A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
×
2040
            else
2041
                w = atanh(z) + im * pi * (unw(logAkp1-logAk) - unw(log1p(z)-log1p(-z)))
728✔
2042
                dd = 2 * exp(p*(logAk+logAkp1)/2) * sinh(p*w) / (Akp1 - Ak);
1,456✔
2043
                A[k,k+1] = A0[k,k+1] * dd
728✔
2044
            end
2045
        end
2046
    end
924✔
2047
end
2048

2049
# Unwinding number
2050
unw(x::Real) = 0
262✔
2051
unw(x::Number) = ceil((imag(x) - pi) / (2 * pi))
1,852✔
2052

2053
# compute A / B for upper quasi-triangular B, possibly overwriting B
2054
function rdiv_quasitriu!(A, B)
1,555✔
2055
    n = checksquare(A)
1,555✔
2056
    AG = copy(A)
1,555✔
2057
    # use Givens rotations to annihilate 2x2 blocks
2058
    @inbounds for k in 1:(n-1)
3,095✔
2059
        s = B[k+1,k]
9,711✔
2060
        iszero(s) && continue  # 1x1 block
4,953✔
2061
        G = first(givens(B[k+1,k+1], s, k, k+1))
85✔
2062
        rmul!(B, G)
400✔
2063
        rmul!(AG, G)
85✔
2064
    end
8,366✔
2065
    return rdiv!(AG, UpperTriangular(B))
1,555✔
2066
end
2067

2068
# End of auxiliary functions for matrix logarithm and matrix power
2069

2070
sqrt(A::UpperTriangular) = sqrt_quasitriu(A)
559✔
2071
function sqrt(A::UnitUpperTriangular{T}) where T
18✔
2072
    B = A.data
18✔
2073
    n = checksquare(B)
18✔
2074
    t = typeof(sqrt(zero(T)))
18✔
2075
    R = Matrix{t}(I, n, n)
18✔
2076
    tt = typeof(zero(t)*zero(t))
18✔
2077
    half = inv(R[1,1]+R[1,1]) # for general, algebraic cases. PR#20214
20✔
2078
    @inbounds for j = 1:n
36✔
2079
        for i = j-1:-1:1
258✔
2080
            r::tt = B[i,j]
516✔
2081
            @simd for k = i+1:j-1
636✔
2082
                r -= R[i,k]*R[k,j]
1,180✔
2083
            end
×
2084
            r==0 || (R[i,j] = half*r)
1,032✔
2085
        end
912✔
2086
    end
258✔
2087
    return UnitUpperTriangular(R)
18✔
2088
end
2089
sqrt(A::LowerTriangular) = copy(transpose(sqrt(copy(transpose(A)))))
7✔
2090
sqrt(A::UnitLowerTriangular) = copy(transpose(sqrt(copy(transpose(A)))))
7✔
2091

2092
# Auxiliary functions for matrix square root
2093

2094
# square root of upper triangular or real upper quasitriangular matrix
2095
function sqrt_quasitriu(A0; blockwidth = eltype(A0) <: Complex ? 512 : 256)
1,294✔
2096
    n = checksquare(A0)
647✔
2097
    T = eltype(A0)
647✔
2098
    Tr = typeof(sqrt(real(zero(T))))
647✔
2099
    Tc = typeof(sqrt(complex(zero(T))))
647✔
2100
    if isreal(A0)
2,107✔
2101
        is_sqrt_real = true
283✔
2102
        if istriu(A0)
283✔
2103
            for i in 1:n
398✔
2104
                Aii = real(A0[i,i])
592✔
2105
                if Aii < zero(Aii)
592✔
2106
                    is_sqrt_real = false
40✔
2107
                    break
40✔
2108
                end
2109
            end
552✔
2110
        end
2111
        if is_sqrt_real
283✔
2112
            R = zeros(Tr, n, n)
27,006✔
2113
            A = real(A0)
243✔
2114
        else
2115
            R = zeros(Tc, n, n)
347✔
2116
            A = A0
323✔
2117
        end
2118
    else
2119
        A = A0
364✔
2120
        R = zeros(Tc, n, n)
364✔
2121
    end
2122
    _sqrt_quasitriu!(R, A; blockwidth=blockwidth, n=n)
888✔
2123
    Rc = eltype(A0) <: Real ? R : complex(R)
741✔
2124
    if A0 isa UpperTriangular
647✔
2125
        return UpperTriangular(Rc)
559✔
2126
    elseif A0 isa UnitUpperTriangular
88✔
2127
        return UnitUpperTriangular(Rc)
×
2128
    else
2129
        return Rc
88✔
2130
    end
2131
end
2132

2133
# in-place recursive sqrt of upper quasi-triangular matrix A from
2134
# Deadman E., Higham N.J., Ralha R. (2013) Blocked Schur Algorithms for Computing the Matrix
2135
# Square Root. Applied Parallel and Scientific Computing. PARA 2012. Lecture Notes in
2136
# Computer Science, vol 7782. https://doi.org/10.1007/978-3-642-36803-5_12
2137
function _sqrt_quasitriu!(R, A; blockwidth=64, n=checksquare(A))
4,121✔
2138
    if n ≤ blockwidth || !(eltype(R) <: BlasFloat) # base case, perform "point" algorithm
2,092✔
2139
        _sqrt_quasitriu_block!(R, A)
2,029✔
2140
    else  # compute blockwise recursion
2141
        split = div(n, 2)
31✔
2142
        iszero(A[split+1, split]) || (split += 1) # don't split 2x2 diagonal block
39✔
2143
        r1 = 1:split
31✔
2144
        r2 = (split + 1):n
31✔
2145
        n1, n2 = split, n - split
31✔
2146
        A11, A12, A22 = @views A[r1,r1], A[r1,r2], A[r2,r2]
31✔
2147
        R11, R12, R22 = @views R[r1,r1], R[r1,r2], R[r2,r2]
31✔
2148
        # solve diagonal blocks recursively
2149
        _sqrt_quasitriu!(R11, A11; blockwidth=blockwidth, n=n1)
31✔
2150
        _sqrt_quasitriu!(R22, A22; blockwidth=blockwidth, n=n2)
31✔
2151
        # solve off-diagonal block
2152
        R12 .= .- A12
62✔
2153
        _sylvester_quasitriu!(R11, R22, R12; blockwidth=blockwidth, nA=n1, nB=n2, raise=false)
31✔
2154
    end
2155
    return R
2,060✔
2156
end
2157

2158
function _sqrt_quasitriu_block!(R, A)
2,029✔
2159
    _sqrt_quasitriu_diag_block!(R, A)
2,029✔
2160
    _sqrt_quasitriu_offdiag_block!(R, A)
2,029✔
2161
    return R
2,029✔
2162
end
2163

2164
function _sqrt_quasitriu_diag_block!(R, A)
2,029✔
2165
    n = size(R, 1)
2,029✔
2166
    ta = eltype(R) <: Complex ? complex(eltype(A)) : eltype(A)
2,029✔
2167
    i = 1
2,029✔
2168
    @inbounds while i < n
2,029✔
2169
        if iszero(A[i + 1, i])
11,269✔
2170
            R[i, i] = sqrt(ta(A[i, i]))
5,701✔
2171
            i += 1
5,701✔
2172
        else
2173
            # this branch is never reached when A is complex triangular
2174
            @views _sqrt_real_2x2!(R[i:(i + 1), i:(i + 1)], A[i:(i + 1), i:(i + 1)])
736✔
2175
            i += 2
736✔
2176
        end
2177
    end
6,437✔
2178
    if i == n
2,029✔
2179
        R[n, n] = sqrt(ta(A[n, n]))
1,591✔
2180
    end
2181
    return R
2,029✔
2182
end
2183

2184
function _sqrt_quasitriu_offdiag_block!(R, A)
2,029✔
2185
    n = size(R, 1)
2,029✔
2186
    j = 1
2,029✔
2187
    @inbounds while j ≤ n
2,029✔
2188
        jsize_is_2 = j < n && !iszero(A[j + 1, j])
12,860✔
2189
        i = j - 1
8,028✔
2190
        while i > 0
66,842✔
2191
            isize_is_2 = i > 1 && !iszero(A[i, i - 1])
69,575✔
2192
            if isize_is_2
58,814✔
2193
                if jsize_is_2
831✔
2194
                    _sqrt_quasitriu_offdiag_block_2x2!(R, A, i - 1, j)
414✔
2195
                else
2196
                    _sqrt_quasitriu_offdiag_block_2x1!(R, A, i - 1, j)
417✔
2197
                end
2198
                i -= 2
831✔
2199
            else
2200
                if jsize_is_2
57,983✔
2201
                    _sqrt_quasitriu_offdiag_block_1x2!(R, A, i, j)
250✔
2202
                else
2203
                    _sqrt_quasitriu_offdiag_block_1x1!(R, A, i, j)
57,734✔
2204
                end
2205
                i -= 1
57,983✔
2206
            end
2207
        end
58,814✔
2208
        j += 2 - !jsize_is_2
8,028✔
2209
    end
8,028✔
2210
    return R
2,029✔
2211
end
2212

2213
# real square root of 2x2 diagonal block of quasi-triangular matrix from real Schur
2214
# decomposition. Eqs 6.8-6.9 and Algorithm 6.5 of
2215
# Higham, 2008, "Functions of Matrices: Theory and Computation", SIAM.
2216
Base.@propagate_inbounds function _sqrt_real_2x2!(R, A)
1,193✔
2217
    # in the real Schur form, A[1, 1] == A[2, 2], and A[2, 1] * A[1, 2] < 0
2218
    θ, a21, a12 = A[1, 1], A[2, 1], A[1, 2]
1,193✔
2219
    # avoid overflow/underflow of μ
2220
    # for real sqrt, |d| ≤ 2 max(|a12|,|a21|)
2221
    μ = sqrt(abs(a12)) * sqrt(abs(a21))
1,193✔
2222
    α = _real_sqrt(θ, μ)
1,307✔
2223
    c = 2α
1,193✔
2224
    R[1, 1] = α
1,193✔
2225
    R[2, 1] = a21 / c
1,193✔
2226
    R[1, 2] = a12 / c
1,193✔
2227
    R[2, 2] = α
1,193✔
2228
    return R
1,193✔
2229
end
2230

2231
# real part of square root of θ+im*μ
2232
@inline function _real_sqrt(θ, μ)
1,193✔
2233
    t = sqrt((abs(θ) + hypot(θ, μ)) / 2)
1,278✔
2234
    return θ ≥ 0 ? t : μ / 2t
1,307✔
2235
end
2236

2237
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_1x1!(R, A, i, j)
57,733✔
2238
    Rii = R[i, i]
57,733✔
2239
    Rjj = R[j, j]
57,733✔
2240
    iszero(Rii) && iszero(Rjj) && return R
57,733✔
2241
    t = eltype(R)
57,732✔
2242
    tt = typeof(zero(t)*zero(t))
57,732✔
2243
    r = tt(-A[i, j])
57,732✔
2244
    @simd for k in (i + 1):(j - 1)
63,322✔
2245
        r += R[i, k] * R[k, j]
2,965,398✔
2246
    end
×
2247
    iszero(r) && return R
57,732✔
2248
    R[i, j] = sylvester(Rii, Rjj, r)
56,956✔
2249
    return R
56,956✔
2250
end
2251

2252
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_1x2!(R, A, i, j)
250✔
2253
    jrange = j:(j + 1)
250✔
2254
    t = eltype(R)
250✔
2255
    tt = typeof(zero(t)*zero(t))
250✔
2256
    r1 = tt(-A[i, j])
250✔
2257
    r2 = tt(-A[i, j + 1])
250✔
2258
    @simd for k in (i + 1):(j - 1)
360✔
2259
        rik = R[i, k]
476✔
2260
        r1 += rik * R[k, j]
476✔
2261
        r2 += rik * R[k, j + 1]
476✔
2262
    end
×
2263
    Rjj = @view R[jrange, jrange]
250✔
2264
    Rij = @view R[i, jrange]
250✔
2265
    Rij[1] = r1
250✔
2266
    Rij[2] = r2
250✔
2267
    _sylvester_1x2!(R[i, i], Rjj, Rij)
250✔
2268
    return R
250✔
2269
end
2270

2271
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_2x1!(R, A, i, j)
417✔
2272
    irange = i:(i + 1)
417✔
2273
    t = eltype(R)
417✔
2274
    tt = typeof(zero(t)*zero(t))
417✔
2275
    r1 = tt(-A[i, j])
417✔
2276
    r2 = tt(-A[i + 1, j])
417✔
2277
    @simd for k in (i + 2):(j - 1)
546✔
2278
        rkj = R[k, j]
1,003✔
2279
        r1 += R[i, k] * rkj
1,003✔
2280
        r2 += R[i + 1, k] * rkj
1,003✔
2281
    end
×
2282
    Rii = @view R[irange, irange]
417✔
2283
    Rij = @view R[irange, j]
417✔
2284
    Rij[1] = r1
417✔
2285
    Rij[2] = r2
417✔
2286
    @views _sylvester_2x1!(Rii, R[j, j], Rij)
417✔
2287
    return R
417✔
2288
end
2289

2290
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_2x2!(R, A, i, j)
414✔
2291
    irange = i:(i + 1)
414✔
2292
    jrange = j:(j + 1)
414✔
2293
    t = eltype(R)
414✔
2294
    tt = typeof(zero(t)*zero(t))
414✔
2295
    for i′ in irange, j′ in jrange
1,242✔
2296
        Cij = tt(-A[i′, j′])
1,656✔
2297
        @simd for k in (i + 2):(j - 1)
2,332✔
2298
            Cij += R[i′, k] * R[k, j′]
3,464✔
2299
        end
×
2300
        R[i′, j′] = Cij
1,656✔
2301
    end
2,070✔
2302
    Rii = @view R[irange, irange]
414✔
2303
    Rjj = @view R[jrange, jrange]
414✔
2304
    Rij = @view R[irange, jrange]
414✔
2305
    if !iszero(Rij) && !all(isnan, Rij)
414✔
2306
        _sylvester_2x2!(Rii, Rjj, Rij)
411✔
2307
    end
2308
    return R
414✔
2309
end
2310

2311
# solve Sylvester's equation AX + XB = -C using blockwise recursion until the dimension of
2312
# A and B are no greater than blockwidth, based on Algorithm 1 from
2313
# Jonsson I, Kågström B. Recursive blocked algorithms for solving triangular systems—
2314
# Part I: one-sided and coupled Sylvester-type matrix equations. (2002) ACM Trans Math Softw.
2315
# 28(4), https://doi.org/10.1145/592843.592845.
2316
# specify raise=false to avoid breaking the recursion if a LAPACKException is thrown when
2317
# computing one of the blocks.
2318
function _sylvester_quasitriu!(A, B, C; blockwidth=64, nA=checksquare(A), nB=checksquare(B), raise=true)
1,154✔
2319
    if 1 ≤ nA ≤ blockwidth && 1 ≤ nB ≤ blockwidth
539✔
2320
        _sylvester_quasitriu_base!(A, B, C; raise=raise)
398✔
2321
    elseif nA ≥ 2nB ≥ 2
141✔
2322
        _sylvester_quasitriu_split1!(A, B, C; blockwidth=blockwidth, nA=nA, nB=nB, raise=raise)
12✔
2323
    elseif nB ≥ 2nA ≥ 2
129✔
2324
        _sylvester_quasitriu_split2!(A, B, C; blockwidth=blockwidth, nA=nA, nB=nB, raise=raise)
12✔
2325
    else
2326
        _sylvester_quasitriu_splitall!(A, B, C; blockwidth=blockwidth, nA=nA, nB=nB, raise=raise)
117✔
2327
    end
2328
    return C
499✔
2329
end
2330
function _sylvester_quasitriu_base!(A, B, C; raise=true)
796✔
2331
    try
398✔
2332
        _, scale = LAPACK.trsyl!('N', 'N', A, B, C)
398✔
2333
        rmul!(C, -inv(scale))
398✔
2334
    catch e
2335
        if !(e isa LAPACKException) || raise
296✔
2336
            throw(e)
148✔
2337
        end
2338
    end
2339
    return C
382✔
2340
end
2341
function _sylvester_quasitriu_split1!(A, B, C; nA=checksquare(A), kwargs...)
24✔
2342
    iA = div(nA, 2)
12✔
2343
    iszero(A[iA + 1, iA]) || (iA += 1)  # don't split 2x2 diagonal block
12✔
2344
    rA1, rA2 = 1:iA, (iA + 1):nA
12✔
2345
    nA1, nA2 = iA, nA-iA
12✔
2346
    A11, A12, A22 = @views A[rA1,rA1], A[rA1,rA2], A[rA2,rA2]
12✔
2347
    C1, C2 = @views C[rA1,:], C[rA2,:]
12✔
2348
    _sylvester_quasitriu!(A22, B, C2; nA=nA2, kwargs...)
24✔
2349
    mul!(C1, A12, C2, true, true)
8✔
2350
    _sylvester_quasitriu!(A11, B, C1; nA=nA1, kwargs...)
16✔
2351
    return C
8✔
2352
end
2353
function _sylvester_quasitriu_split2!(A, B, C; nB=checksquare(B), kwargs...)
24✔
2354
    iB = div(nB, 2)
12✔
2355
    iszero(B[iB + 1, iB]) || (iB += 1)  # don't split 2x2 diagonal block
12✔
2356
    rB1, rB2 = 1:iB, (iB + 1):nB
12✔
2357
    nB1, nB2 = iB, nB-iB
12✔
2358
    B11, B12, B22 = @views B[rB1,rB1], B[rB1,rB2], B[rB2,rB2]
12✔
2359
    C1, C2 = @views C[:,rB1], C[:,rB2]
12✔
2360
    _sylvester_quasitriu!(A, B11, C1; nB=nB1, kwargs...)
24✔
2361
    mul!(C2, C1, B12, true, true)
8✔
2362
    _sylvester_quasitriu!(A, B22, C2; nB=nB2, kwargs...)
16✔
2363
    return C
8✔
2364
end
2365
function _sylvester_quasitriu_splitall!(A, B, C; nA=checksquare(A), nB=checksquare(B), kwargs...)
234✔
2366
    iA = div(nA, 2)
117✔
2367
    iszero(A[iA + 1, iA]) || (iA += 1)  # don't split 2x2 diagonal block
128✔
2368
    iB = div(nB, 2)
117✔
2369
    iszero(B[iB + 1, iB]) || (iB += 1)  # don't split 2x2 diagonal block
136✔
2370
    rA1, rA2 = 1:iA, (iA + 1):nA
117✔
2371
    nA1, nA2 = iA, nA-iA
117✔
2372
    rB1, rB2 = 1:iB, (iB + 1):nB
117✔
2373
    nB1, nB2 = iB, nB-iB
117✔
2374
    A11, A12, A22 = @views A[rA1,rA1], A[rA1,rA2], A[rA2,rA2]
117✔
2375
    B11, B12, B22 = @views B[rB1,rB1], B[rB1,rB2], B[rB2,rB2]
117✔
2376
    C11, C21, C12, C22 = @views C[rA1,rB1], C[rA2,rB1], C[rA1,rB2], C[rA2,rB2]
117✔
2377
    _sylvester_quasitriu!(A22, B11, C21; nA=nA2, nB=nB1, kwargs...)
129✔
2378
    mul!(C11, A12, C21, true, true)
101✔
2379
    _sylvester_quasitriu!(A11, B11, C11; nA=nA1, nB=nB1, kwargs...)
109✔
2380
    mul!(C22, C21, B12, true, true)
101✔
2381
    _sylvester_quasitriu!(A22, B22, C22; nA=nA2, nB=nB2, kwargs...)
109✔
2382
    mul!(C12, A12, C22, true, true)
101✔
2383
    mul!(C12, C11, B12, true, true)
101✔
2384
    _sylvester_quasitriu!(A11, B22, C12; nA=nA1, nB=nB2, kwargs...)
109✔
2385
    return C
101✔
2386
end
2387

2388
# End of auxiliary functions for matrix square root
2389

2390
# Generic eigensystems
2391
eigvals(A::AbstractTriangular) = diag(A)
100✔
2392
function eigvecs(A::AbstractTriangular{T}) where T
4✔
2393
    TT = promote_type(T, Float32)
4✔
2394
    if TT <: BlasFloat
4✔
2395
        return eigvecs(convert(AbstractMatrix{TT}, A))
4✔
2396
    else
2397
        throw(ArgumentError("eigvecs type $(typeof(A)) not supported. Please submit a pull request."))
×
2398
    end
2399
end
2400
det(A::UnitUpperTriangular{T}) where {T} = one(T)
7✔
2401
det(A::UnitLowerTriangular{T}) where {T} = one(T)
7✔
2402
logdet(A::UnitUpperTriangular{T}) where {T} = zero(T)
7✔
2403
logdet(A::UnitLowerTriangular{T}) where {T} = zero(T)
7✔
2404
logabsdet(A::UnitUpperTriangular{T}) where {T} = zero(T), one(T)
7✔
2405
logabsdet(A::UnitLowerTriangular{T}) where {T} = zero(T), one(T)
7✔
2406
det(A::UpperTriangular) = prod(diag(A.data))
253✔
2407
det(A::LowerTriangular) = prod(diag(A.data))
7✔
2408
function logabsdet(A::Union{UpperTriangular{T},LowerTriangular{T}}) where T
28✔
2409
    sgn = one(T)
28✔
2410
    abs_det = zero(real(T))
28✔
2411
    @inbounds for i in 1:size(A,1)
56✔
2412
        diag_i = A.data[i,i]
252✔
2413
        sgn *= sign(diag_i)
252✔
2414
        abs_det += log(abs(diag_i))
292✔
2415
    end
476✔
2416
    return abs_det, sgn
28✔
2417
end
2418

2419
eigen(A::AbstractTriangular) = Eigen(eigvals(A), eigvecs(A))
20✔
2420

2421
# Generic singular systems
2422
for func in (:svd, :svd!, :svdvals)
2423
    @eval begin
2424
        ($func)(A::AbstractTriangular; kwargs...) = ($func)(copyto!(similar(parent(A)), A); kwargs...)
112✔
2425
    end
2426
end
2427

2428
factorize(A::AbstractTriangular) = A
28✔
2429

2430
# disambiguation methods: /(Adjoint of AbsVec, <:AbstractTriangular)
2431
/(u::AdjointAbsVec, A::Union{LowerTriangular,UpperTriangular}) = adjoint(adjoint(A) \ u.parent)
×
2432
/(u::AdjointAbsVec, A::Union{UnitLowerTriangular,UnitUpperTriangular}) = adjoint(adjoint(A) \ u.parent)
×
2433
# disambiguation methods: /(Transpose of AbsVec, <:AbstractTriangular)
2434
/(u::TransposeAbsVec, A::Union{LowerTriangular,UpperTriangular}) = transpose(transpose(A) \ u.parent)
×
2435
/(u::TransposeAbsVec, A::Union{UnitLowerTriangular,UnitUpperTriangular}) = transpose(transpose(A) \ u.parent)
×
2436
# disambiguation methods: /(Transpose of AbsVec, Adj/Trans of <:AbstractTriangular)
2437
for (tritype, comptritype) in ((:LowerTriangular, :UpperTriangular),
2438
                               (:UnitLowerTriangular, :UnitUpperTriangular),
2439
                               (:UpperTriangular, :LowerTriangular),
2440
                               (:UnitUpperTriangular, :UnitLowerTriangular))
2441
    @eval /(u::TransposeAbsVec, A::$tritype{<:Any,<:Adjoint}) = transpose($comptritype(conj(parent(parent(A)))) \ u.parent)
×
2442
    @eval /(u::TransposeAbsVec, A::$tritype{<:Any,<:Transpose}) = transpose(transpose(A) \ u.parent)
×
2443
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc